From 0ad5083ac95c54b90db6825567fa8a31b470fc82 Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Mon, 10 Jan 2022 17:23:26 +0100 Subject: [PATCH 01/21] Abstract media servers content into interfaces --- src/.idea/.idea.Ombi/.idea/contentModel.xml | 4 +- src/Ombi.Api.Emby/Models/EmbyMediaType.cs | 10 ---- .../Models/JellyfinMediaType.cs | 10 ---- .../Request/ExistingPlexRequestRuleTests.cs | 2 +- src/Ombi.Core/Engine/RecentlyAddedEngine.cs | 30 +++++------ .../Rules/Request/ExistingPlexRequestRule.cs | 2 +- .../Rule/Rules/Search/PlexAvailabilityRule.cs | 10 ++-- .../Jobs/Emby/EmbyContentSync.cs | 6 +-- .../Jobs/Jellyfin/JellyfinContentSync.cs | 6 +-- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 29 +++++----- .../Jobs/Ombi/RefreshMetadata.cs | 12 ++--- .../Jobs/Plex/PlexContentSync.cs | 20 +++---- .../Jobs/Plex/PlexEpisodeSync.cs | 2 +- src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs | 37 ------------- src/Ombi.Store/Entities/EmbyContent.cs | 10 +--- src/Ombi.Store/Entities/EmbyEpisode.cs | 2 +- .../Entities/IMediaServerContent.cs | 54 +++++++++++++++++++ src/Ombi.Store/Entities/JellyfinContent.cs | 10 +--- src/Ombi.Store/Entities/JellyfinEpisode.cs | 2 +- src/Ombi.Store/Entities/PlexEpisode.cs | 2 +- src/Ombi.Store/Entities/PlexServerContent.cs | 11 ++-- .../Repository/IPlexContentRepository.cs | 2 +- .../Repository/PlexContentRepository.cs | 2 +- 23 files changed, 128 insertions(+), 147 deletions(-) delete mode 100644 src/Ombi.Api.Emby/Models/EmbyMediaType.cs delete mode 100644 src/Ombi.Api.Jellyfin/Models/JellyfinMediaType.cs delete mode 100644 src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs create mode 100644 src/Ombi.Store/Entities/IMediaServerContent.cs diff --git a/src/.idea/.idea.Ombi/.idea/contentModel.xml b/src/.idea/.idea.Ombi/.idea/contentModel.xml index 4affa7aee..438274536 100644 --- a/src/.idea/.idea.Ombi/.idea/contentModel.xml +++ b/src/.idea/.idea.Ombi/.idea/contentModel.xml @@ -929,7 +929,7 @@ - + @@ -1876,7 +1876,7 @@ - + diff --git a/src/Ombi.Api.Emby/Models/EmbyMediaType.cs b/src/Ombi.Api.Emby/Models/EmbyMediaType.cs deleted file mode 100644 index 7b33f8972..000000000 --- a/src/Ombi.Api.Emby/Models/EmbyMediaType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ombi.Api.Emby.Models -{ - public enum EmbyMediaType - { - Movie = 0, - Series = 1, - Music = 2, - Episode = 3 - } -} \ No newline at end of file diff --git a/src/Ombi.Api.Jellyfin/Models/JellyfinMediaType.cs b/src/Ombi.Api.Jellyfin/Models/JellyfinMediaType.cs deleted file mode 100644 index 2c4f75be0..000000000 --- a/src/Ombi.Api.Jellyfin/Models/JellyfinMediaType.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ombi.Api.Jellyfin.Models -{ - public enum JellyfinMediaType - { - Movie = 0, - Series = 1, - Music = 2, - Episode = 3 - } -} \ No newline at end of file diff --git a/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs b/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs index f5a362303..a4a278815 100644 --- a/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs @@ -182,7 +182,7 @@ private void SetupMockData() { new PlexServerContent { - Type = PlexMediaTypeEntity.Show, + Type = MediaType.Series, TheMovieDbId = "1", Title = "Test", ReleaseYear = "2001", diff --git a/src/Ombi.Core/Engine/RecentlyAddedEngine.cs b/src/Ombi.Core/Engine/RecentlyAddedEngine.cs index d597ec80b..25aba5547 100644 --- a/src/Ombi.Core/Engine/RecentlyAddedEngine.cs +++ b/src/Ombi.Core/Engine/RecentlyAddedEngine.cs @@ -30,26 +30,26 @@ public RecentlyAddedEngine(IPlexContentRepository plex, IEmbyContentRepository e public IEnumerable GetRecentlyAddedMovies(DateTime from, DateTime to) { - var plexMovies = _plex.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Movie && x.AddedAt > from && x.AddedAt < to); - var embyMovies = _emby.GetAll().Where(x => x.Type == EmbyMediaType.Movie && x.AddedAt > from && x.AddedAt < to); - var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == JellyfinMediaType.Movie && x.AddedAt > from && x.AddedAt < to); + var plexMovies = _plex.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to); + var embyMovies = _emby.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to); + var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == MediaType.Movie && x.AddedAt > from && x.AddedAt < to); return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies).Take(30); } public IEnumerable GetRecentlyAddedMovies() { - var plexMovies = _plex.GetAll().Where(x => x.Type == PlexMediaTypeEntity.Movie); - var embyMovies = _emby.GetAll().Where(x => x.Type == EmbyMediaType.Movie); - var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == JellyfinMediaType.Movie); + var plexMovies = _plex.GetAll().Where(x => x.Type == MediaType.Movie); + var embyMovies = _emby.GetAll().Where(x => x.Type == MediaType.Movie); + var jellyfinMovies = _jellyfin.GetAll().Where(x => x.Type == MediaType.Movie); return GetRecentlyAddedMovies(plexMovies, embyMovies, jellyfinMovies); } public IEnumerable GetRecentlyAddedTv(DateTime from, DateTime to, bool groupBySeason) { - var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show && x.AddedAt > from && x.AddedAt < to); - var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == EmbyMediaType.Series && x.AddedAt > from && x.AddedAt < to); - var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == JellyfinMediaType.Series && x.AddedAt > from && x.AddedAt < to); + var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to); + var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to); + var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series && x.AddedAt > from && x.AddedAt < to); return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason).Take(30); } @@ -57,9 +57,9 @@ public IEnumerable GetRecentlyAddedTv(DateTime from, DateT public IEnumerable GetRecentlyAddedTv(bool groupBySeason) { - var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show); - var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == EmbyMediaType.Series); - var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == JellyfinMediaType.Series); + var plexTv = _plex.GetAll().Include(x => x.Seasons).Include(x => x.Episodes).Where(x => x.Type == MediaType.Series); + var embyTv = _emby.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series); + var jellyfinTv = _jellyfin.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series); return GetRecentlyAddedTv(plexTv, embyTv, jellyfinTv, groupBySeason); } @@ -76,7 +76,7 @@ public async Task UpdateRecentlyAddedDatabase() { continue; } - if (p.Type == PlexMediaTypeEntity.Movie) + if (p.Type == MediaType.Movie) { recentlyAddedLog.Add(new RecentlyAddedLog { @@ -114,7 +114,7 @@ public async Task UpdateRecentlyAddedDatabase() { continue; } - if (e.Type == EmbyMediaType.Movie) + if (e.Type == MediaType.Movie) { recentlyAddedLog.Add(new RecentlyAddedLog { @@ -152,7 +152,7 @@ public async Task UpdateRecentlyAddedDatabase() { continue; } - if (e.Type == JellyfinMediaType.Movie) + if (e.Type == MediaType.Movie) { recentlyAddedLog.Add(new RecentlyAddedLog { diff --git a/src/Ombi.Core/Rule/Rules/Request/ExistingPlexRequestRule.cs b/src/Ombi.Core/Rule/Rules/Request/ExistingPlexRequestRule.cs index ef38fb973..40be1c73e 100644 --- a/src/Ombi.Core/Rule/Rules/Request/ExistingPlexRequestRule.cs +++ b/src/Ombi.Core/Rule/Rules/Request/ExistingPlexRequestRule.cs @@ -32,7 +32,7 @@ public async Task Execute(BaseRequest obj) { var tvRequest = (ChildRequests) obj; - var tvContent = _plexContent.GetAll().Include(x => x.Episodes).Where(x => x.Type == PlexMediaTypeEntity.Show); + var tvContent = _plexContent.GetAll().Include(x => x.Episodes).Where(x => x.Type == MediaType.Series); // We need to do a check on the TVDBId var anyMovieDbMatches = await tvContent.FirstOrDefaultAsync(x => x.TheMovieDbId.Length > 0 && x.TheMovieDbId == tvRequest.Id.ToString()); if (anyMovieDbMatches == null) diff --git a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs index 42e97f5f7..c84eb610c 100644 --- a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs @@ -33,7 +33,7 @@ public async Task Execute(SearchViewModel obj) var useId = false; var useTvDb = false; - PlexMediaTypeEntity type = ConvertType(obj.Type); + MediaType type = ConvertType(obj.Type); if (obj.ImdbId.HasValue()) { @@ -115,12 +115,12 @@ public async Task Execute(SearchViewModel obj) return Success(); } - private PlexMediaTypeEntity ConvertType(RequestType type) => + private MediaType ConvertType(RequestType type) => type switch { - RequestType.Movie => PlexMediaTypeEntity.Movie, - RequestType.TvShow => PlexMediaTypeEntity.Show, - _ => PlexMediaTypeEntity.Movie, + RequestType.Movie => MediaType.Movie, + RequestType.TvShow => MediaType.Series, + _ => MediaType.Movie, }; } } \ No newline at end of file diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs index 5f9c294a7..dd9be69e0 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs @@ -16,7 +16,7 @@ using Ombi.Store.Entities; using Ombi.Store.Repository; using Quartz; -using EmbyMediaType = Ombi.Store.Entities.EmbyMediaType; +using MediaType = Ombi.Store.Entities.MediaType; namespace Ombi.Schedule.Jobs.Emby { @@ -165,7 +165,7 @@ private async Task ProcessTv(EmbyServers server, bool recentlyAdded, string pare ImdbId = tvShow.ProviderIds?.Imdb, TheMovieDbId = tvShow.ProviderIds?.Tmdb, Title = tvShow.Name, - Type = EmbyMediaType.Series, + Type = MediaType.Series, EmbyId = tvShow.Id, Url = EmbyHelper.GetEmbyMediaUrl(tvShow.Id, server?.ServerId, server.ServerHostname), AddedAt = DateTime.UtcNow @@ -255,7 +255,7 @@ private async Task ProcessMovies(EmbyMovie movieInfo, ICollection c ImdbId = movieInfo.ProviderIds.Imdb, TheMovieDbId = movieInfo.ProviderIds?.Tmdb, Title = movieInfo.Name, - Type = EmbyMediaType.Movie, + Type = MediaType.Movie, EmbyId = movieInfo.Id, Url = EmbyHelper.GetEmbyMediaUrl(movieInfo.Id, server?.ServerId, server.ServerHostname), AddedAt = DateTime.UtcNow, diff --git a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs index 2a950fcf4..8906e3a60 100644 --- a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs @@ -14,7 +14,7 @@ using Ombi.Store.Entities; using Ombi.Store.Repository; using Quartz; -using JellyfinMediaType = Ombi.Store.Entities.JellyfinMediaType; +using MediaType = Ombi.Store.Entities.MediaType; namespace Ombi.Schedule.Jobs.Jellyfin { @@ -143,7 +143,7 @@ private async Task ProcessTv(JellyfinServers server, string parentId = default) ImdbId = tvShow.ProviderIds?.Imdb, TheMovieDbId = tvShow.ProviderIds?.Tmdb, Title = tvShow.Name, - Type = JellyfinMediaType.Series, + Type = MediaType.Series, JellyfinId = tvShow.Id, Url = JellyfinHelper.GetJellyfinMediaUrl(tvShow.Id, server?.ServerId, server.ServerHostname), AddedAt = DateTime.UtcNow @@ -223,7 +223,7 @@ private async Task ProcessMovies(JellyfinMovie movieInfo, ICollection x.Type == PlexMediaTypeEntity.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var embyContentLocalDataset = embyContent.Where(x => x.Type == EmbyMediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var jellyfinContentLocalDataset = jellyfinContent.Where(x => x.Type == JellyfinMediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var plexContentLocalDataset = plexContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var embyContentLocalDataset = embyContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var jellyfinContentLocalDataset = jellyfinContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var plexContentMoviesToSend = plexContentLocalDataset.Where(x => !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); var embyContentMoviesToSend = embyContentLocalDataset.Where(x => !addedEmbyMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); var jellyfinContentMoviesToSend = jellyfinContentLocalDataset.Where(x => !addedJellyfinMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); @@ -158,9 +159,9 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) _log.LogInformation("Albums to send: {0}", lidarrContentAlbumsToSend.Count()); // Find the movies that do not yet have MovieDbIds - var needsMovieDbPlex = plexContent.Where(x => x.Type == PlexMediaTypeEntity.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var needsMovieDbEmby = embyContent.Where(x => x.Type == EmbyMediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var needsMovieDbJellyfin = jellyfinContent.Where(x => x.Type == JellyfinMediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var needsMovieDbPlex = plexContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var needsMovieDbEmby = embyContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var needsMovieDbJellyfin = jellyfinContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); var newPlexMovies = await GetMoviesWithoutId(addedPlexMovieLogIds, needsMovieDbPlex); var newEmbyMovies = await GetMoviesWithoutId(addedEmbyMoviesLogIds, needsMovieDbEmby); var newJellyfinMovies = await GetMoviesWithoutId(addedJellyfinMoviesLogIds, needsMovieDbJellyfin); @@ -188,9 +189,9 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) 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 jellyfinm = jellyfinContent.Where(x => x.Type == JellyfinMediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10); + var plexm = plexContent.Where(x => x.Type == MediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10); + var embym = embyContent.Where(x => x.Type == MediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10); + var jellyfinm = jellyfinContent.Where(x => x.Type == MediaType.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 jellyfint = _jellyfin.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet(); @@ -284,7 +285,7 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) } foreach (var e in embyContentMoviesToSend) { - if (e.Type == EmbyMediaType.Movie) + if (e.Type == MediaType.Movie) { recentlyAddedLog.Add(new RecentlyAddedLog { @@ -311,7 +312,7 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) foreach (var e in jellyfinContentMoviesToSend) { - if (e.Type == JellyfinMediaType.Movie) + if (e.Type == MediaType.Movie) { recentlyAddedLog.Add(new RecentlyAddedLog { @@ -570,9 +571,9 @@ private async Task BuildHtml(IQueryable plexContentTo var ombiSettings = await _ombiSettings.GetSettingsAsync(); var sb = new StringBuilder(); - var plexMovies = plexContentToSend.Where(x => x.Type == PlexMediaTypeEntity.Movie); - var embyMovies = embyContentToSend.Where(x => x.Type == EmbyMediaType.Movie); - var jellyfinMovies = jellyfinContentToSend.Where(x => x.Type == JellyfinMediaType.Movie); + var plexMovies = plexContentToSend.Where(x => x.Type == MediaType.Movie); + var embyMovies = embyContentToSend.Where(x => x.Type == MediaType.Movie); + var jellyfinMovies = jellyfinContentToSend.Where(x => x.Type == MediaType.Movie); if ((plexMovies.Any() || embyMovies.Any() || jellyfinMovies.Any()) && !settings.DisableMovies) { sb.Append("

New Movies



"); diff --git a/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs b/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs index a24d07da0..2421d5af0 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/RefreshMetadata.cs @@ -116,12 +116,12 @@ private async Task StartPlex() { // Ensure we check that we have not linked this item to a request var allMovies = await _plexRepo.GetAll().Where(x => - x.Type == PlexMediaTypeEntity.Movie && x.RequestId == null && (x.TheMovieDbId == null || x.ImdbId == null)).ToListAsync(); + x.Type == MediaType.Movie && x.RequestId == null && (x.TheMovieDbId == null || x.ImdbId == null)).ToListAsync(); await StartPlexMovies(allMovies); // Now Tv var allTv = await _plexRepo.GetAll().Where(x => - x.Type == PlexMediaTypeEntity.Show && x.RequestId == null && (x.TheMovieDbId == null || x.ImdbId == null || x.TvDbId == null)).ToListAsync(); + x.Type == MediaType.Series && x.RequestId == null && (x.TheMovieDbId == null || x.ImdbId == null || x.TvDbId == null)).ToListAsync(); await StartPlexTv(allTv); } @@ -178,7 +178,7 @@ private async Task StartPlexTv(List allTv) private async Task StartEmbyTv() { var allTv = await _embyRepo.GetAll().Where(x => - x.Type == EmbyMediaType.Series && (x.TheMovieDbId == null || x.ImdbId == null || x.TvDbId == null)).ToListAsync(); + x.Type == MediaType.Series && (x.TheMovieDbId == null || x.ImdbId == null || x.TvDbId == null)).ToListAsync(); foreach (var show in allTv) { @@ -213,7 +213,7 @@ private async Task StartEmbyTv() private async Task StartJellyfinTv() { var allTv = await _jellyfinRepo.GetAll().Where(x => - x.Type == JellyfinMediaType.Series && (x.TheMovieDbId == null || x.ImdbId == null || x.TvDbId == null)).ToListAsync(); + x.Type == MediaType.Series && (x.TheMovieDbId == null || x.ImdbId == null || x.TvDbId == null)).ToListAsync(); foreach (var show in allTv) { @@ -278,7 +278,7 @@ private async Task StartPlexMovies(List allMovies) private async Task StartEmbyMovies(EmbySettings settings) { var allMovies = await _embyRepo.GetAll().Where(x => - x.Type == EmbyMediaType.Movie && (x.TheMovieDbId == null || x.ImdbId == null)).ToListAsync(); + x.Type == MediaType.Movie && (x.TheMovieDbId == null || x.ImdbId == null)).ToListAsync(); foreach (var movie in allMovies) { movie.ImdbId.HasValue(); @@ -333,7 +333,7 @@ private async Task StartEmbyMovies(EmbySettings settings) private async Task StartJellyfinMovies(JellyfinSettings settings) { var allMovies = await _jellyfinRepo.GetAll().Where(x => - x.Type == JellyfinMediaType.Movie && (x.TheMovieDbId == null || x.ImdbId == null)).ToListAsync(); + x.Type == MediaType.Movie && (x.TheMovieDbId == null || x.ImdbId == null)).ToListAsync(); foreach (var movie in allMovies) { movie.ImdbId.HasValue(); diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index 3289c5a24..c36bfa1aa 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -182,7 +182,7 @@ private async Task ProcessServer(PlexServers servers, bool rec foreach (var content in allContent.OrderByDescending(x => x.viewGroup)) { Logger.LogDebug($"Got type '{content.viewGroup}' to process"); - if (content.viewGroup.Equals(PlexMediaType.Episode.ToString(), StringComparison.InvariantCultureIgnoreCase)) + if (content.viewGroup.Equals(MediaType.Episode.ToString(), StringComparison.InvariantCultureIgnoreCase)) { Logger.LogDebug("Found some episodes, this must be a recently added sync"); var count = 0; @@ -230,7 +230,7 @@ private async Task ProcessServer(PlexServers servers, bool rec episodesProcessed.AddRange(episodesAdded.Select(x => x.Id)); } } - if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.InvariantCultureIgnoreCase)) + if (content.viewGroup.Equals(MediaType.Series.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // Process Shows Logger.LogDebug("Processing TV Shows"); @@ -260,7 +260,7 @@ private async Task ProcessServer(PlexServers servers, bool rec await Repo.SaveChangesAsync(); } - if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.InvariantCultureIgnoreCase)) + if (content.viewGroup.Equals(MediaType.Movie.ToString(), StringComparison.InvariantCultureIgnoreCase)) { await MovieLoop(servers, content, contentToAdd, contentProcessed); } @@ -301,7 +301,7 @@ public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet { var existing = await Repo.GetFirstContentByCustom(x => x.Title == movie.title && x.ReleaseYear == movie.year.ToString() - && x.Type == PlexMediaTypeEntity.Movie); + && x.Type == MediaType.Movie); // The rating key keeps changing //var existing = await Repo.GetByKey(movie.ratingKey); if (existing != null) @@ -349,7 +349,7 @@ public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet AddedAt = DateTime.Now, Key = movie.ratingKey, ReleaseYear = movie.year.ToString(), - Type = PlexMediaTypeEntity.Movie, + Type = MediaType.Movie, Title = movie.title, Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey), Seasons = new List(), @@ -411,7 +411,7 @@ private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet x.Title == show.title && x.ReleaseYear == show.year.ToString() - && x.Type == PlexMediaTypeEntity.Show); + && x.Type == MediaType.Series); // Just double check the rating key, since this is our unique constraint var existingKey = await Repo.GetByKey(show.ratingKey); @@ -553,7 +553,7 @@ private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet() @@ -567,19 +567,19 @@ private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet - x.ImdbId == item.ImdbId && x.Type == PlexMediaTypeEntity.Show); + x.ImdbId == item.ImdbId && x.Type == MediaType.Series); } if (item.TheMovieDbId.HasValue()) { existingMovieDbId = await Repo.GetAll().AnyAsync(x => - x.TheMovieDbId == item.TheMovieDbId && x.Type == PlexMediaTypeEntity.Show); + x.TheMovieDbId == item.TheMovieDbId && x.Type == MediaType.Series); } if (item.TvDbId.HasValue()) { existingTvDbId = await Repo.GetAll().AnyAsync(x => - x.TvDbId == item.TvDbId && x.Type == PlexMediaTypeEntity.Show); + x.TvDbId == item.TvDbId && x.Type == MediaType.Series); } if (existingImdb || existingTvDbId || existingMovieDbId) diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs index 50c5d1f39..6fbbb7612 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs @@ -83,7 +83,7 @@ private async Task Cache(PlexServers settings) var sections = await _api.GetLibrarySections(settings.PlexAuthToken, settings.FullUri); // Filter the libSections - var tvSections = sections.MediaContainer.Directory.Where(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)); + var tvSections = sections.MediaContainer.Directory.Where(x => x.type.Equals(MediaType.Series.ToString(), StringComparison.CurrentCultureIgnoreCase)); foreach (var section in tvSections) { diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs b/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs deleted file mode 100644 index 2e2e9229e..000000000 --- a/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs +++ /dev/null @@ -1,37 +0,0 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2017 Jamie Rees -// File: PlexContentCacher.cs -// Created By: Jamie Rees -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// ************************************************************************/ -#endregion - - -namespace Ombi.Schedule.Jobs -{ - public enum PlexMediaType - { - Movie = 0, - Show = 1, - Episode = 2, - } -} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/EmbyContent.cs b/src/Ombi.Store/Entities/EmbyContent.cs index 348573f28..847896833 100644 --- a/src/Ombi.Store/Entities/EmbyContent.cs +++ b/src/Ombi.Store/Entities/EmbyContent.cs @@ -32,7 +32,7 @@ namespace Ombi.Store.Entities { [Table("EmbyContent")] - public class EmbyContent : Entity + public class EmbyContent : Entity, IMediaServerContent { public string Title { get; set; } @@ -41,7 +41,7 @@ public class EmbyContent : Entity /// public string ProviderId { get; set; } public string EmbyId { get; set; } - public EmbyMediaType Type { get; set; } + public MediaType Type { get; set; } public DateTime AddedAt { get; set; } public string ImdbId { get; set; } @@ -62,10 +62,4 @@ public class EmbyContent : Entity public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); } - public enum EmbyMediaType - { - Movie = 0, - Series = 1, - Music = 2 - } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/EmbyEpisode.cs b/src/Ombi.Store/Entities/EmbyEpisode.cs index e4e5b6a4b..4ec0814f1 100644 --- a/src/Ombi.Store/Entities/EmbyEpisode.cs +++ b/src/Ombi.Store/Entities/EmbyEpisode.cs @@ -32,7 +32,7 @@ namespace Ombi.Store.Entities { [Table("EmbyEpisode")] - public class EmbyEpisode : Entity + public class EmbyEpisode : Entity, IMediaServerEpisode { public string Title { get; set; } public string EmbyId { get; set; } diff --git a/src/Ombi.Store/Entities/IMediaServerContent.cs b/src/Ombi.Store/Entities/IMediaServerContent.cs new file mode 100644 index 000000000..e7d16734e --- /dev/null +++ b/src/Ombi.Store/Entities/IMediaServerContent.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities +{ + public interface IMediaServerContent + { + public string Title { get; set; } + public string ImdbId { get; set; } + public string TvDbId { get; set; } + public string TheMovieDbId { get; set; } + public MediaType Type { get; set; } + + public string Url { get; set; } + + public ICollection Episodes { get; set; } + + public DateTime AddedAt { get; set; } + + [NotMapped] + public bool HasImdb => !string.IsNullOrEmpty(ImdbId); + + [NotMapped] + public bool HasTvDb => !string.IsNullOrEmpty(TvDbId); + + [NotMapped] + public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); + } + + public interface IMediaServerEpisode + { + public int EpisodeNumber { get; set; } + public int SeasonNumber { get; set; } + public string Title { get; set; } + /// + /// The Season key + /// + /// + /// The parent key. + /// + + + public IMediaServerContent Series { get; set; } + } + + public enum MediaType + { + Movie = 0, + Series = 1, + Music = 2, + Episode = 3 + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/JellyfinContent.cs b/src/Ombi.Store/Entities/JellyfinContent.cs index 857457bde..2e7058ea5 100644 --- a/src/Ombi.Store/Entities/JellyfinContent.cs +++ b/src/Ombi.Store/Entities/JellyfinContent.cs @@ -32,7 +32,7 @@ namespace Ombi.Store.Entities { [Table("JellyfinContent")] - public class JellyfinContent : Entity + public class JellyfinContent : Entity, IMediaServerContent { public string Title { get; set; } @@ -41,7 +41,7 @@ public class JellyfinContent : Entity /// public string ProviderId { get; set; } public string JellyfinId { get; set; } - public JellyfinMediaType Type { get; set; } + public MediaType Type { get; set; } public DateTime AddedAt { get; set; } public string ImdbId { get; set; } @@ -62,10 +62,4 @@ public class JellyfinContent : Entity public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); } - public enum JellyfinMediaType - { - Movie = 0, - Series = 1, - Music = 2 - } } diff --git a/src/Ombi.Store/Entities/JellyfinEpisode.cs b/src/Ombi.Store/Entities/JellyfinEpisode.cs index f2c2f820d..88f47f426 100644 --- a/src/Ombi.Store/Entities/JellyfinEpisode.cs +++ b/src/Ombi.Store/Entities/JellyfinEpisode.cs @@ -32,7 +32,7 @@ namespace Ombi.Store.Entities { [Table("JellyfinEpisode")] - public class JellyfinEpisode : Entity + public class JellyfinEpisode : Entity, IMediaServerEpisode { public string Title { get; set; } public string JellyfinId { get; set; } diff --git a/src/Ombi.Store/Entities/PlexEpisode.cs b/src/Ombi.Store/Entities/PlexEpisode.cs index 3acca8f3b..12239fefc 100644 --- a/src/Ombi.Store/Entities/PlexEpisode.cs +++ b/src/Ombi.Store/Entities/PlexEpisode.cs @@ -3,7 +3,7 @@ namespace Ombi.Store.Entities { [Table("PlexEpisode")] - public class PlexEpisode : Entity + public class PlexEpisode : Entity, IMediaServerEpisode { public int EpisodeNumber { get; set; } public int SeasonNumber { get; set; } diff --git a/src/Ombi.Store/Entities/PlexServerContent.cs b/src/Ombi.Store/Entities/PlexServerContent.cs index f8e0e01d4..ec4aa1186 100644 --- a/src/Ombi.Store/Entities/PlexServerContent.cs +++ b/src/Ombi.Store/Entities/PlexServerContent.cs @@ -32,17 +32,18 @@ namespace Ombi.Store.Entities { [Table("PlexServerContent")] - public class PlexServerContent : Entity + public class PlexServerContent : Entity, IMediaServerContent { public string Title { get; set; } public string ReleaseYear { get; set; } public string ImdbId { get; set; } public string TvDbId { get; set; } public string TheMovieDbId { get; set; } - public PlexMediaTypeEntity Type { get; set; } + public MediaType Type { get; set; } public string Url { get; set; } + //public IMediaServerEpisode Episode { get; set; } public ICollection Episodes { get; set; } public ICollection Seasons { get; set; } @@ -73,10 +74,4 @@ public class PlexSeasonsContent : Entity public int SeasonKey { get; set; } public int ParentKey { get; set; } } - - public enum PlexMediaTypeEntity - { - Movie = 0, - Show = 1 - } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IPlexContentRepository.cs b/src/Ombi.Store/Repository/IPlexContentRepository.cs index 38c013cb1..abb482308 100644 --- a/src/Ombi.Store/Repository/IPlexContentRepository.cs +++ b/src/Ombi.Store/Repository/IPlexContentRepository.cs @@ -12,7 +12,7 @@ public interface IPlexContentRepository : IExternalRepository { Task ContentExists(string providerId); Task Get(string providerId, ProviderType type); - Task GetByType(string providerId, ProviderType type, PlexMediaTypeEntity plexType); + Task GetByType(string providerId, ProviderType type, MediaType plexType); Task GetByKey(int key); Task Update(PlexServerContent existingContent); IQueryable GetAllEpisodes(); diff --git a/src/Ombi.Store/Repository/PlexContentRepository.cs b/src/Ombi.Store/Repository/PlexContentRepository.cs index 31b3bad11..917a44b55 100644 --- a/src/Ombi.Store/Repository/PlexContentRepository.cs +++ b/src/Ombi.Store/Repository/PlexContentRepository.cs @@ -79,7 +79,7 @@ public async Task Get(string providerId, ProviderType type) return null; } - public async Task GetByType(string providerId, ProviderType type, PlexMediaTypeEntity plexType) + public async Task GetByType(string providerId, ProviderType type, MediaType plexType) { switch (type) { From aeeba5b22d752faf8e62e70b55d1b5c4f4974729 Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Tue, 11 Jan 2022 15:11:18 +0100 Subject: [PATCH 02/21] Media server entities into abstract classes --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 20 +++++----- .../Jobs/Plex/PlexAvailabilityChecker.cs | 2 +- src/Ombi.Store/Context/ExternalContext.cs | 15 +++---- src/Ombi.Store/Entities/EmbyContent.cs | 22 +---------- src/Ombi.Store/Entities/EmbyEpisode.cs | 13 ++++--- .../Entities/IMediaServerContent.cs | 4 +- src/Ombi.Store/Entities/JellyfinContent.cs | 22 +---------- src/Ombi.Store/Entities/JellyfinEpisode.cs | 13 ++++--- src/Ombi.Store/Entities/MediaServerContent.cs | 39 +++++++++++++++++++ src/Ombi.Store/Entities/PlexEpisode.cs | 20 ++++------ src/Ombi.Store/Entities/PlexServerContent.cs | 27 ++++--------- 11 files changed, 90 insertions(+), 107 deletions(-) create mode 100644 src/Ombi.Store/Entities/MediaServerContent.cs diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index b4cc3ba5e..c68d3c483 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -914,10 +914,10 @@ private async Task ProcessPlexTv(HashSet plexContent, StringBuilder var series = new List(); foreach (var plexEpisode in plexContent) { - var alreadyAdded = series.FirstOrDefault(x => x.Key == plexEpisode.Series.Key); + var alreadyAdded = series.FirstOrDefault(x => x.Key == plexEpisode.PlexSeries.Key); if (alreadyAdded != null) { - var episodeExists = alreadyAdded.Episodes.Any(x => x.Key == plexEpisode.Key); + var episodeExists = alreadyAdded.PlexEpisodes.Any(x => x.Key == plexEpisode.Key); if (!episodeExists) { alreadyAdded.Episodes.Add(plexEpisode); @@ -925,8 +925,8 @@ private async Task ProcessPlexTv(HashSet plexContent, StringBuilder } else { - plexEpisode.Series.Episodes = new List { plexEpisode }; - series.Add(plexEpisode.Series); + plexEpisode.Series.Episodes = new List { plexEpisode }; + series.Add(plexEpisode.PlexSeries); } } @@ -1042,18 +1042,18 @@ private async Task ProcessEmbyTv(HashSet embyContent, StringBuilder var series = new List(); foreach (var episode in embyContent) { - var alreadyAdded = series.FirstOrDefault(x => x.EmbyId == episode.Series.EmbyId); + var alreadyAdded = series.FirstOrDefault(x => x.EmbyId == episode.EmbySeries.EmbyId); if (alreadyAdded != null) { alreadyAdded.Episodes.Add(episode); } else { - episode.Series.Episodes = new List + episode.Series.Episodes = new List { episode }; - series.Add(episode.Series); + series.Add(episode.EmbySeries); } } @@ -1145,18 +1145,18 @@ private async Task ProcessJellyfinTv(HashSet jellyfinContent, S var series = new List(); foreach (var episode in jellyfinContent) { - var alreadyAdded = series.FirstOrDefault(x => x.JellyfinId == episode.Series.JellyfinId); + var alreadyAdded = series.FirstOrDefault(x => x.JellyfinId == episode.JellyfinSeries.JellyfinId); if (alreadyAdded != null) { alreadyAdded.Episodes.Add(episode); } else { - episode.Series.Episodes = new List + episode.Series.Episodes = new List { episode }; - series.Add(episode.Series); + series.Add(episode.JellyfinSeries); } } diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs index 7a05f794b..822a0f197 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs @@ -106,7 +106,7 @@ private async Task ProcessTv(List tv) // 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()); + x.PlexSeries.ReleaseYear == child.ParentRequest.ReleaseDate.Year.ToString()); } diff --git a/src/Ombi.Store/Context/ExternalContext.cs b/src/Ombi.Store/Context/ExternalContext.cs index ce121fe10..b6f8d6485 100644 --- a/src/Ombi.Store/Context/ExternalContext.cs +++ b/src/Ombi.Store/Context/ExternalContext.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using Microsoft.EntityFrameworkCore; using Ombi.Helpers; using Ombi.Store.Entities; @@ -42,20 +43,20 @@ protected ExternalContext(DbContextOptions options) protected override void OnModelCreating(ModelBuilder builder) { - builder.Entity().HasMany(x => x.Episodes) - .WithOne(x => x.Series) + builder.Entity().HasMany(x => (ICollection) x.Episodes) + .WithOne(x => (PlexServerContent) x.Series) .HasPrincipalKey(x => x.Key) .HasForeignKey(x => x.GrandparentKey); builder.Entity() - .HasOne(p => p.Series) - .WithMany(b => b.Episodes) + .HasOne(p => (EmbyContent) p.Series) + .WithMany(b => (ICollection) b.Episodes) .HasPrincipalKey(x => x.EmbyId) .HasForeignKey(p => p.ParentId); builder.Entity() - .HasOne(p => p.Series) - .WithMany(b => b.Episodes) + .HasOne(p => (JellyfinContent) p.Series) + .WithMany(b => (ICollection) b.Episodes) .HasPrincipalKey(x => x.JellyfinId) .HasForeignKey(p => p.ParentId); diff --git a/src/Ombi.Store/Entities/EmbyContent.cs b/src/Ombi.Store/Entities/EmbyContent.cs index 847896833..07fb1110e 100644 --- a/src/Ombi.Store/Entities/EmbyContent.cs +++ b/src/Ombi.Store/Entities/EmbyContent.cs @@ -32,34 +32,14 @@ namespace Ombi.Store.Entities { [Table("EmbyContent")] - public class EmbyContent : Entity, IMediaServerContent + public class EmbyContent : MediaServerContent { - public string Title { get; set; } /// /// OBSOLETE, Cannot delete due to DB migration issues with SQLite /// public string ProviderId { get; set; } public string EmbyId { get; set; } - public MediaType Type { get; set; } - public DateTime AddedAt { get; set; } - - public string ImdbId { get; set; } - public string TheMovieDbId { get; set; } - public string TvDbId { get; set; } - - public string Url { get; set; } - - public ICollection Episodes { get; set; } - - [NotMapped] - public bool HasImdb => !string.IsNullOrEmpty(ImdbId); - - [NotMapped] - public bool HasTvDb => !string.IsNullOrEmpty(TvDbId); - - [NotMapped] - public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/EmbyEpisode.cs b/src/Ombi.Store/Entities/EmbyEpisode.cs index 4ec0814f1..5b31fa3ac 100644 --- a/src/Ombi.Store/Entities/EmbyEpisode.cs +++ b/src/Ombi.Store/Entities/EmbyEpisode.cs @@ -32,12 +32,9 @@ namespace Ombi.Store.Entities { [Table("EmbyEpisode")] - public class EmbyEpisode : Entity, IMediaServerEpisode + public class EmbyEpisode : MediaServerEpisode { - public string Title { get; set; } public string EmbyId { get; set; } - public int EpisodeNumber { get; set; } - public int SeasonNumber { get; set; } public string ParentId { get; set; } /// /// NOT USED @@ -47,7 +44,11 @@ public class EmbyEpisode : Entity, IMediaServerEpisode public string TvDbId { get; set; } public string ImdbId { get; set; } public string TheMovieDbId { get; set; } - - public EmbyContent Series { get; set; } + [NotMapped] + public EmbyContent EmbySeries + { + get => (EmbyContent)Series; + set => Series = value; + } } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/IMediaServerContent.cs b/src/Ombi.Store/Entities/IMediaServerContent.cs index e7d16734e..1eb7f7606 100644 --- a/src/Ombi.Store/Entities/IMediaServerContent.cs +++ b/src/Ombi.Store/Entities/IMediaServerContent.cs @@ -4,7 +4,7 @@ namespace Ombi.Store.Entities { - public interface IMediaServerContent + public interface IMediaServerContent { public string Title { get; set; } public string ImdbId { get; set; } @@ -28,7 +28,7 @@ public interface IMediaServerContent public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); } - public interface IMediaServerEpisode + public interface IMediaServerEpisode { public int EpisodeNumber { get; set; } public int SeasonNumber { get; set; } diff --git a/src/Ombi.Store/Entities/JellyfinContent.cs b/src/Ombi.Store/Entities/JellyfinContent.cs index 2e7058ea5..a3744adeb 100644 --- a/src/Ombi.Store/Entities/JellyfinContent.cs +++ b/src/Ombi.Store/Entities/JellyfinContent.cs @@ -32,34 +32,14 @@ namespace Ombi.Store.Entities { [Table("JellyfinContent")] - public class JellyfinContent : Entity, IMediaServerContent + public class JellyfinContent : MediaServerContent { - public string Title { get; set; } /// /// OBSOLETE, Cannot delete due to DB migration issues with SQLite /// public string ProviderId { get; set; } public string JellyfinId { get; set; } - public MediaType Type { get; set; } - public DateTime AddedAt { get; set; } - - public string ImdbId { get; set; } - public string TheMovieDbId { get; set; } - public string TvDbId { get; set; } - - public string Url { get; set; } - - public ICollection Episodes { get; set; } - - [NotMapped] - public bool HasImdb => !string.IsNullOrEmpty(ImdbId); - - [NotMapped] - public bool HasTvDb => !string.IsNullOrEmpty(TvDbId); - - [NotMapped] - public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); } } diff --git a/src/Ombi.Store/Entities/JellyfinEpisode.cs b/src/Ombi.Store/Entities/JellyfinEpisode.cs index 88f47f426..cff3cf486 100644 --- a/src/Ombi.Store/Entities/JellyfinEpisode.cs +++ b/src/Ombi.Store/Entities/JellyfinEpisode.cs @@ -32,12 +32,9 @@ namespace Ombi.Store.Entities { [Table("JellyfinEpisode")] - public class JellyfinEpisode : Entity, IMediaServerEpisode + public class JellyfinEpisode : MediaServerEpisode { - public string Title { get; set; } public string JellyfinId { get; set; } - public int EpisodeNumber { get; set; } - public int SeasonNumber { get; set; } public string ParentId { get; set; } /// /// NOT USED @@ -47,7 +44,11 @@ public class JellyfinEpisode : Entity, IMediaServerEpisode public string TvDbId { get; set; } public string ImdbId { get; set; } public string TheMovieDbId { get; set; } - - public JellyfinContent Series { get; set; } + [NotMapped] + public JellyfinContent JellyfinSeries + { + get => (JellyfinContent)Series; + set => Series = value; + } } } diff --git a/src/Ombi.Store/Entities/MediaServerContent.cs b/src/Ombi.Store/Entities/MediaServerContent.cs new file mode 100644 index 000000000..a1aee79c4 --- /dev/null +++ b/src/Ombi.Store/Entities/MediaServerContent.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities +{ + public abstract class MediaServerContent: Entity, IMediaServerContent + { + public string Title { get; set; } + public string ImdbId { get; set; } + public string TvDbId { get; set; } + public string TheMovieDbId { get; set; } + public MediaType Type { get; set; } + + public string Url { get; set; } + + public ICollection Episodes { get; set; } + + public DateTime AddedAt { get; set; } + + [NotMapped] + public bool HasImdb => !string.IsNullOrEmpty(ImdbId); + + [NotMapped] + public bool HasTvDb => !string.IsNullOrEmpty(TvDbId); + + [NotMapped] + public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); + } + + public abstract class MediaServerEpisode: Entity, IMediaServerEpisode + { + public int EpisodeNumber { get; set; } + public int SeasonNumber { get; set; } + public string Title { get; set; } + + public IMediaServerContent Series { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/PlexEpisode.cs b/src/Ombi.Store/Entities/PlexEpisode.cs index 12239fefc..4c7e3300b 100644 --- a/src/Ombi.Store/Entities/PlexEpisode.cs +++ b/src/Ombi.Store/Entities/PlexEpisode.cs @@ -3,28 +3,22 @@ namespace Ombi.Store.Entities { [Table("PlexEpisode")] - public class PlexEpisode : Entity, IMediaServerEpisode + public class PlexEpisode : MediaServerEpisode { - public int EpisodeNumber { get; set; } - public int SeasonNumber { get; set; } public int Key { get; set; } // RatingKey - public string Title { get; set; } - /// - /// The Season key - /// /// /// The parent key. /// public int ParentKey { get; set; } - /// - /// The Series key - /// /// /// The grandparent key. /// public int GrandparentKey { get; set; } - - - public PlexServerContent Series { get; set; } + [NotMapped] + public PlexServerContent PlexSeries + { + get => (PlexServerContent)Series; + set => Series = value; + } } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/PlexServerContent.cs b/src/Ombi.Store/Entities/PlexServerContent.cs index ec4aa1186..c2e6b8de0 100644 --- a/src/Ombi.Store/Entities/PlexServerContent.cs +++ b/src/Ombi.Store/Entities/PlexServerContent.cs @@ -32,38 +32,25 @@ namespace Ombi.Store.Entities { [Table("PlexServerContent")] - public class PlexServerContent : Entity, IMediaServerContent + public class PlexServerContent : MediaServerContent { - public string Title { get; set; } public string ReleaseYear { get; set; } - public string ImdbId { get; set; } - public string TvDbId { get; set; } - public string TheMovieDbId { get; set; } - public MediaType Type { get; set; } - - public string Url { get; set; } - - //public IMediaServerEpisode Episode { get; set; } - public ICollection Episodes { get; set; } public ICollection Seasons { get; set; } /// /// Plex's internal ID for this item /// public int Key { get; set; } - public DateTime AddedAt { get; set; } public string Quality { get; set; } public int? RequestId { get; set; } - - [NotMapped] - public bool HasImdb => !string.IsNullOrEmpty(ImdbId); - - [NotMapped] - public bool HasTvDb => !string.IsNullOrEmpty(TvDbId); - + [NotMapped] - public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); + public ICollection PlexEpisodes + { + get => (ICollection)Episodes; + set => Episodes = (ICollection)value; + } } [Table("PlexSeasonsContent")] From a309f50d1598b63d6b4105b0e7aa019d236727cd Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Tue, 11 Jan 2022 15:34:19 +0100 Subject: [PATCH 03/21] Abstract media server content repository --- .../Repository/IEmbyContentRepository.cs | 13 +++++-------- .../Repository/IJellyfinContentRepository.cs | 13 +++++-------- .../Repository/IMediaServerContentRepository.cs | 17 +++++++++++++++++ .../Repository/IPlexContentRepository.cs | 9 ++------- 4 files changed, 29 insertions(+), 23 deletions(-) create mode 100644 src/Ombi.Store/Repository/IMediaServerContentRepository.cs diff --git a/src/Ombi.Store/Repository/IEmbyContentRepository.cs b/src/Ombi.Store/Repository/IEmbyContentRepository.cs index a893e9aca..e3857cfb2 100644 --- a/src/Ombi.Store/Repository/IEmbyContentRepository.cs +++ b/src/Ombi.Store/Repository/IEmbyContentRepository.cs @@ -6,19 +6,16 @@ namespace Ombi.Store.Repository { - public interface IEmbyContentRepository : IRepository + public interface IEmbyContentRepository : IMediaServerContentRepository { + Task GetByEmbyId(string embyId); + Task GetEpisodeByEmbyId(string key); + + // TODO: merge these with IJellyfinContentRepository IQueryable Get(); Task GetByTheMovieDbId(string mov); Task GetByTvDbId(string tv); Task GetByImdbId(string imdbid); - Task GetByEmbyId(string embyId); - Task Update(EmbyContent existingContent); - IQueryable GetAllEpisodes(); - Task Add(EmbyEpisode content); - Task GetEpisodeByEmbyId(string key); - Task AddRange(IEnumerable content); - void UpdateWithoutSave(EmbyContent existingContent); } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IJellyfinContentRepository.cs b/src/Ombi.Store/Repository/IJellyfinContentRepository.cs index ff1f2d7dc..eed242f0b 100644 --- a/src/Ombi.Store/Repository/IJellyfinContentRepository.cs +++ b/src/Ombi.Store/Repository/IJellyfinContentRepository.cs @@ -6,19 +6,16 @@ namespace Ombi.Store.Repository { - public interface IJellyfinContentRepository : IRepository + public interface IJellyfinContentRepository : IMediaServerContentRepository { + Task GetByJellyfinId(string jellyfinId); + Task GetEpisodeByJellyfinId(string key); + + // TODO: merge these with IEmbyContentRepository IQueryable Get(); Task GetByTheMovieDbId(string mov); Task GetByTvDbId(string tv); Task GetByImdbId(string imdbid); - Task GetByJellyfinId(string jellyfinId); - Task Update(JellyfinContent existingContent); - IQueryable GetAllEpisodes(); - Task Add(JellyfinEpisode content); - Task GetEpisodeByJellyfinId(string key); - Task AddRange(IEnumerable content); - void UpdateWithoutSave(JellyfinContent existingContent); } } diff --git a/src/Ombi.Store/Repository/IMediaServerContentRepository.cs b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs new file mode 100644 index 000000000..1abb25b66 --- /dev/null +++ b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ombi.Store.Entities; + +namespace Ombi.Store.Repository +{ + public interface IMediaServerContentRepository : IExternalRepository where Content : Entity + { + Task Update(Content existingContent); + IQueryable GetAllEpisodes(); + Task Add(Episode content); + Task AddRange(IEnumerable content); + + void UpdateWithoutSave(Content existingContent); + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IPlexContentRepository.cs b/src/Ombi.Store/Repository/IPlexContentRepository.cs index abb482308..bbdd256de 100644 --- a/src/Ombi.Store/Repository/IPlexContentRepository.cs +++ b/src/Ombi.Store/Repository/IPlexContentRepository.cs @@ -8,23 +8,18 @@ namespace Ombi.Store.Repository { - public interface IPlexContentRepository : IExternalRepository + public interface IPlexContentRepository : IMediaServerContentRepository { Task ContentExists(string providerId); Task Get(string providerId, ProviderType type); - Task GetByType(string providerId, ProviderType type, MediaType plexType); + Task GetByType(string providerId, ProviderType type, MediaType MediaServerType); Task GetByKey(int key); - Task Update(PlexServerContent existingContent); - IQueryable GetAllEpisodes(); - Task Add(PlexEpisode content); Task GetEpisodeByKey(int key); - Task AddRange(IEnumerable content); IEnumerable GetWhereContentByCustom(Expression> predicate); Task GetFirstContentByCustom(Expression> predicate); Task DeleteEpisode(PlexEpisode content); void DeleteWithoutSave(PlexServerContent content); void DeleteWithoutSave(PlexEpisode content); Task UpdateRange(IEnumerable existingContent); - void UpdateWithoutSave(PlexServerContent existingContent); } } \ No newline at end of file From 229a89f48a17c20ef72d1d16eb445892ceba7f59 Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Tue, 11 Jan 2022 19:17:25 +0100 Subject: [PATCH 04/21] First pass at newsletter refactoring --- .../Rules/Search/AvailabilityRuleHelper.cs | 66 +- .../Rule/Rules/Search/EmbyAvailabilityRule.cs | 7 +- .../Rules/Search/JellyfinAvailabilityRule.cs | 7 +- .../Jobs/Emby/EmbyAvaliabilityChecker.cs | 2 +- .../Jellyfin/JellyfinAvaliabilityChecker.cs | 2 +- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 592 +++--------------- .../Jobs/Plex/PlexAvailabilityChecker.cs | 5 +- .../Jobs/Plex/PlexContentSync.cs | 4 +- .../Jobs/Plex/PlexEpisodeSync.cs | 2 +- src/Ombi.Store/Entities/EmbyEpisode.cs | 14 +- .../Entities/IMediaServerContent.cs | 4 + src/Ombi.Store/Entities/JellyfinEpisode.cs | 12 + src/Ombi.Store/Entities/MediaServerContent.cs | 3 + src/Ombi.Store/Entities/PlexEpisode.cs | 16 +- .../Repository/EmbyContentRepository.cs | 18 +- .../IMediaServerContentRepository.cs | 9 +- .../IMediaServerContentRepositoryLight.cs | 16 + .../Repository/JellyfinContentRepository.cs | 18 +- .../Repository/PlexContentRepository.cs | 18 +- 19 files changed, 198 insertions(+), 617 deletions(-) create mode 100644 src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs diff --git a/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs b/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs index fe062e851..630e4ac81 100644 --- a/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs +++ b/src/Ombi.Core/Rule/Rules/Search/AvailabilityRuleHelper.cs @@ -46,10 +46,10 @@ public static void CheckForUnairedEpisodes(SearchTvShowViewModel search) } } - public static async Task SingleEpisodeCheck(bool useImdb, IQueryable allEpisodes, EpisodeRequests episode, - SeasonRequests season, PlexServerContent item, bool useTheMovieDb, bool useTvDb, ILogger log) + public static async Task SingleEpisodeCheck(bool useImdb, IQueryable allEpisodes, EpisodeRequests episode, + SeasonRequests season, IMediaServerContent item, bool useTheMovieDb, bool useTvDb, ILogger log) { - PlexEpisode epExists = null; + IMediaServerEpisode epExists = null; try { @@ -79,66 +79,6 @@ public static async Task SingleEpisodeCheck(bool useImdb, IQueryable allEpisodes, EpisodeRequests episode, - SeasonRequests season, EmbyContent item, bool useTheMovieDb, bool useTvDb) - { - EmbyEpisode epExists = null; - if (useImdb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.ImdbId == item.ImdbId); - } - - if (useTheMovieDb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.TheMovieDbId == item.TheMovieDbId); - } - - if (useTvDb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.TvDbId == item.TvDbId); - } - - if (epExists != null) - { - episode.Available = true; - } - } - public static async Task SingleEpisodeCheck(bool useImdb, IQueryable allEpisodes, EpisodeRequests episode, - SeasonRequests season, JellyfinContent item, bool useTheMovieDb, bool useTvDb) - { - JellyfinEpisode epExists = null; - if (useImdb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.ImdbId == item.ImdbId); - } - - if (useTheMovieDb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.TheMovieDbId == item.TheMovieDbId); - } - - if (useTvDb) - { - epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && - x.Series.TvDbId == item.TvDbId); - } - if (epExists != null) { episode.Available = true; diff --git a/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs index 7f6718a6b..027f22e8b 100644 --- a/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; using Ombi.Core.Settings; @@ -13,13 +14,15 @@ namespace Ombi.Core.Rule.Rules.Search { public class EmbyAvailabilityRule : BaseSearchRule, IRules { - public EmbyAvailabilityRule(IEmbyContentRepository repo, ISettingsService s) + public EmbyAvailabilityRule(IEmbyContentRepository repo, ILogger log, ISettingsService s) { EmbyContentRepository = repo; + Log = log; EmbySettings = s; } private IEmbyContentRepository EmbyContentRepository { get; } + private ILogger Log { get; } private ISettingsService EmbySettings { get; } public async Task Execute(SearchViewModel obj) @@ -89,7 +92,7 @@ public async Task Execute(SearchViewModel obj) { foreach (var episode in season.Episodes) { - await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb); + await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb, Log); } } } diff --git a/src/Ombi.Core/Rule/Rules/Search/JellyfinAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/JellyfinAvailabilityRule.cs index c51645112..dbbfc8da5 100644 --- a/src/Ombi.Core/Rule/Rules/Search/JellyfinAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/JellyfinAvailabilityRule.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; using Ombi.Core.Settings; @@ -13,13 +14,15 @@ namespace Ombi.Core.Rule.Rules.Search { public class JellyfinAvailabilityRule : BaseSearchRule, IRules { - public JellyfinAvailabilityRule(IJellyfinContentRepository repo, ISettingsService s) + public JellyfinAvailabilityRule(IJellyfinContentRepository repo, ILogger log, ISettingsService s) { JellyfinContentRepository = repo; + Log = log; JellyfinSettings = s; } private IJellyfinContentRepository JellyfinContentRepository { get; } + private ILogger Log { get; } private ISettingsService JellyfinSettings { get; } public async Task Execute(SearchViewModel obj) @@ -104,7 +107,7 @@ public async Task Execute(SearchViewModel obj) { foreach (var episode in season.Episodes) { - await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb); + await AvailabilityRuleHelper.SingleEpisodeCheck(useImdb, allEpisodes, episode, season, item, useTheMovieDb, useTvDb, Log); } } } diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs index 608d6cb82..852530be4 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyAvaliabilityChecker.cs @@ -124,7 +124,7 @@ private async Task ProcessTv() var tvDbId = child.ParentRequest.TvDbId; var imdbId = child.ParentRequest.ImdbId; - IQueryable seriesEpisodes = null; + IQueryable seriesEpisodes = null; if (useImdb) { seriesEpisodes = embyEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString()); diff --git a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinAvaliabilityChecker.cs b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinAvaliabilityChecker.cs index 1a621ebce..125b27fc3 100644 --- a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinAvaliabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinAvaliabilityChecker.cs @@ -151,7 +151,7 @@ private async Task ProcessTv() var tvDbId = child.ParentRequest.TvDbId; var imdbId = child.ParentRequest.ImdbId; - IQueryable seriesEpisodes = null; + IQueryable seriesEpisodes = null; if (useImdb) { seriesEpisodes = jellyfinEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString()); diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index c68d3c483..92a8019be 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -124,18 +124,22 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) 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 jellyfinContent = _jellyfin.GetAll().Include(x => x.Episodes).AsNoTracking(); - var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable); + // MOVIES + var plexContent = (IQueryable)_plex.GetAll().Include(x => x.Episodes).AsNoTracking(); + var embyContent = (IQueryable)_emby.GetAll().Include(x => x.Episodes).AsNoTracking(); + var jellyfinContent = (IQueryable)_jellyfin.GetAll().Include(x => x.Episodes).AsNoTracking(); - var addedLog = _recentlyAddedLog.GetAll().ToList(); + var plexContentMoviesToSend = await getMoviesContent(plexContent, RecentlyAddedType.Plex); + var embyContentMoviesToSend = await getMoviesContent(embyContent, RecentlyAddedType.Emby); + var jellyfinContentMoviesToSend = await getMoviesContent(jellyfinContent, RecentlyAddedType.Jellyfin); - HashSet addedPlexMovieLogIds, addedEmbyMoviesLogIds, addedJellyfinMoviesLogIds; + // MUSIC + var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable); + var addedLog = _recentlyAddedLog.GetAll().ToList(); HashSet addedAlbumLogIds; - GetRecentlyAddedMoviesData(addedLog, out addedPlexMovieLogIds, out addedEmbyMoviesLogIds, out addedJellyfinMoviesLogIds, out addedAlbumLogIds); + GetRecentlyAddedMoviesData(addedLog, out addedAlbumLogIds); + // EPISODES var addedPlexEpisodesLogIds = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Episode); var addedEmbyEpisodesLogIds = @@ -145,39 +149,14 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) // Filter out the ones that we haven't sent yet - var plexContentLocalDataset = plexContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var embyContentLocalDataset = embyContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var jellyfinContentLocalDataset = jellyfinContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - - var plexContentMoviesToSend = plexContentLocalDataset.Where(x => !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); - var embyContentMoviesToSend = embyContentLocalDataset.Where(x => !addedEmbyMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); - var jellyfinContentMoviesToSend = jellyfinContentLocalDataset.Where(x => !addedJellyfinMoviesLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); 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("Jellyfin Movies to send: {0}", jellyfinContentMoviesToSend.Count()); _log.LogInformation("Albums to send: {0}", lidarrContentAlbumsToSend.Count()); - // Find the movies that do not yet have MovieDbIds - var needsMovieDbPlex = plexContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var needsMovieDbEmby = embyContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var needsMovieDbJellyfin = jellyfinContent.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var newPlexMovies = await GetMoviesWithoutId(addedPlexMovieLogIds, needsMovieDbPlex); - var newEmbyMovies = await GetMoviesWithoutId(addedEmbyMoviesLogIds, needsMovieDbEmby); - var newJellyfinMovies = await GetMoviesWithoutId(addedJellyfinMoviesLogIds, needsMovieDbJellyfin); - plexContentMoviesToSend = plexContentMoviesToSend.Union(newPlexMovies).ToHashSet(); - embyContentMoviesToSend = embyContentMoviesToSend.Union(newEmbyMovies).ToHashSet(); - jellyfinContentMoviesToSend = jellyfinContentMoviesToSend.Union(newJellyfinMovies).ToHashSet(); - - plexContentMoviesToSend = plexContentMoviesToSend.DistinctBy(x => x.Id).ToHashSet(); - embyContentMoviesToSend = embyContentMoviesToSend.DistinctBy(x => x.Id).ToHashSet(); - jellyfinContentMoviesToSend = jellyfinContentMoviesToSend.DistinctBy(x => x.Id).ToHashSet(); - var plexEpisodesToSend = - FilterPlexEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), addedPlexEpisodesLogIds); - var embyEpisodesToSend = FilterEmbyEpisodes(_emby.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), + FilterEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), addedPlexEpisodesLogIds); + var embyEpisodesToSend = FilterEpisodes(_emby.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), addedEmbyEpisodesLogIds); - var jellyfinEpisodesToSend = FilterJellyfinEpisodes(_jellyfin.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), + var jellyfinEpisodesToSend = FilterEpisodes(_jellyfin.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), addedJellyfinEpisodesLogIds); _log.LogInformation("Plex Episodes to send: {0}", plexEpisodesToSend.Count()); @@ -193,14 +172,36 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) var embym = embyContent.Where(x => x.Type == MediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10); var jellyfinm = jellyfinContent.Where(x => x.Type == MediaType.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 jellyfint = _jellyfin.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.AddedAt).Take(10).ToHashSet(); + var embyt = _emby.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet(); + var jellyfint = _jellyfin.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet(); var lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet(); - body = await BuildHtml(plexm, embym, jellyfinm, plext, embyt, jellyfint, lidarr, settings, embySettings, jellyfinSettings, plexSettings); + + var moviesProviders = new List>() { + plexm, + embym, + jellyfinm + }; + var seriesProviders = new List>() { + plext, + embyt, + jellyfint + }; + body = await BuildHtml(moviesProviders, seriesProviders, lidarr, settings, embySettings, jellyfinSettings, plexSettings); } else { - body = await BuildHtml(plexContentMoviesToSend.AsQueryable(), embyContentMoviesToSend.AsQueryable(), jellyfinContentMoviesToSend.AsQueryable(), plexEpisodesToSend, embyEpisodesToSend, jellyfinEpisodesToSend, lidarrContentAlbumsToSend, settings, embySettings, jellyfinSettings, plexSettings); + var moviesProviders = new List>() { + plexContentMoviesToSend.AsQueryable(), + embyContentMoviesToSend.AsQueryable(), + jellyfinContentMoviesToSend.AsQueryable() + }; + var seriesProviders = new List>() { + plexEpisodesToSend, + embyEpisodesToSend, + jellyfinEpisodesToSend + }; + + body = await BuildHtml(moviesProviders, seriesProviders, lidarrContentAlbumsToSend, settings, embySettings, jellyfinSettings, plexSettings); if (body.IsNullOrEmpty()) { return; @@ -224,7 +225,7 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) if (!users.Any()) { return; - } + } var messageContent = ParseTemplate(template, customization); var email = new NewsletterTemplate(); @@ -376,21 +377,32 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) .SendAsync(NotificationHub.NotificationEvent, "Newsletter Finished"); } - private void GetRecentlyAddedMoviesData(List addedLog, out HashSet addedPlexMovieLogIds, out HashSet addedEmbyMoviesLogIds, out HashSet addedJellyfinMoviesLogIds, out HashSet addedAlbumLogIds) + private void GetRecentlyAddedMoviesData(List addedLog, out HashSet addedAlbumLogIds) { - var plexParent = addedLog.Where(x => x.Type == RecentlyAddedType.Plex && x.ContentType == ContentType.Parent).ToList(); - addedPlexMovieLogIds = plexParent != null && plexParent.Any() ? (plexParent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet()) : new HashSet(); - - var embyParent = addedLog.Where(x => x.Type == RecentlyAddedType.Emby && x.ContentType == ContentType.Parent); - addedEmbyMoviesLogIds = embyParent != null && embyParent.Any() ? (embyParent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet()) : new HashSet(); - - var jellyFinParent = addedLog.Where(x => x.Type == RecentlyAddedType.Jellyfin && x.ContentType == ContentType.Parent); - addedJellyfinMoviesLogIds = jellyFinParent != null && jellyFinParent.Any() ? (jellyFinParent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet()) : new HashSet(); - var lidarrParent = addedLog.Where(x => x.Type == RecentlyAddedType.Lidarr && x.ContentType == ContentType.Album); addedAlbumLogIds = lidarrParent != null && lidarrParent.Any() ? (lidarrParent?.Select(x => x.AlbumId)?.ToHashSet() ?? new HashSet()) : new HashSet(); } + private async Task> getMoviesContent(IQueryable content, RecentlyAddedType recentlyAddedType) + { + var localDataset = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + // Filter out the ones that we haven't sent yet + var addedLog = _recentlyAddedLog.GetAll().ToList(); + var plexParent = addedLog.Where(x => x.Type == recentlyAddedType + && x.ContentType == ContentType.Parent).ToList(); + var addedPlexMovieLogIds = plexParent != null && plexParent.Any() ? (plexParent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet()) : new HashSet(); + var plexContentMoviesToSend = localDataset.Where(x => !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); + _log.LogInformation("Movies to send: {0}", plexContentMoviesToSend.Count()); + + // Find the movies that do not yet have MovieDbIds + var needsMovieDbPlex = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var newPlexMovies = await GetMoviesWithoutId(addedPlexMovieLogIds, needsMovieDbPlex); + plexContentMoviesToSend = plexContentMoviesToSend.Union(newPlexMovies).ToHashSet(); + + return plexContentMoviesToSend.DistinctBy(x => x.Id).ToHashSet(); + + } + public static string GenerateUnsubscribeLink(string applicationUrl, string id) { if (!applicationUrl.HasValue() || !id.HasValue()) @@ -406,7 +418,7 @@ public static string GenerateUnsubscribeLink(string applicationUrl, string id) return b.ToString(); } - private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDbPlex) + private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDbPlex) { foreach (var movie in needsMovieDbPlex) { @@ -420,35 +432,7 @@ private async Task> GetMoviesWithoutId(HashSet a return result.ToHashSet(); } - private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDbPlex) - { - foreach (var movie in needsMovieDbPlex) - { - var id = await _refreshMetadata.GetTheMovieDbId(false, true, null, movie.ImdbId, movie.Title, true); - movie.TheMovieDbId = id.ToString(); - } - - var result = needsMovieDbPlex.Where(x => x.HasTheMovieDb && !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); - await UpdateTheMovieDbId(result); - // Filter them out now - return result.ToHashSet(); - } - - private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDbJellyfin) - { - foreach (var movie in needsMovieDbJellyfin) - { - var id = await _refreshMetadata.GetTheMovieDbId(false, true, null, movie.ImdbId, movie.Title, true); - movie.TheMovieDbId = id.ToString(); - } - - var result = needsMovieDbJellyfin.Where(x => x.HasTheMovieDb && !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); - await UpdateTheMovieDbId(result); - // Filter them out now - return result.ToHashSet(); - } - - private async Task UpdateTheMovieDbId(IEnumerable content) + private async Task UpdateTheMovieDbId(IEnumerable content) { foreach (var movie in content) { @@ -467,79 +451,15 @@ private async Task UpdateTheMovieDbId(IEnumerable content) await _plex.SaveChangesAsync(); } - private async Task UpdateTheMovieDbId(IEnumerable content) - { - foreach (var movie in content) - { - if (!movie.HasTheMovieDb) - { - continue; - } - var entity = await _emby.Find(movie.Id); - entity.TheMovieDbId = movie.TheMovieDbId; - _emby.UpdateWithoutSave(entity); - } - await _plex.SaveChangesAsync(); - } - - private async Task UpdateTheMovieDbId(IEnumerable content) - { - foreach (var movie in content) - { - if (!movie.HasTheMovieDb) - { - continue; - } - var entity = await _jellyfin.Find(movie.Id); - entity.TheMovieDbId = movie.TheMovieDbId; - _jellyfin.UpdateWithoutSave(entity); - } - await _plex.SaveChangesAsync(); - } - public async Task Execute(IJobExecutionContext job) { var newsletterSettings = await _newsletterSettings.GetSettingsAsync(); await Start(newsletterSettings, false); } - private HashSet FilterPlexEpisodes(IEnumerable source, IEnumerable recentlyAdded) - { - var itemsToReturn = new HashSet(); - foreach (var ep in source.Where(x => x.Series.HasTvDb)) - { - var tvDbId = StringHelper.IntParseLinq(ep.Series.TvDbId); - if (recentlyAdded.Any(x => x.ContentId == tvDbId && x.EpisodeNumber == ep.EpisodeNumber && x.SeasonNumber == ep.SeasonNumber)) - { - continue; - } - - itemsToReturn.Add(ep); - } - - return itemsToReturn; - } - - private HashSet FilterEmbyEpisodes(IEnumerable source, IEnumerable recentlyAdded) + private HashSet FilterEpisodes(IEnumerable source, IEnumerable recentlyAdded) { - var itemsToReturn = new HashSet(); - foreach (var ep in source.Where(x => x.Series.HasTvDb)) - { - var tvDbId = StringHelper.IntParseLinq(ep.Series.TvDbId); - if (recentlyAdded.Any(x => x.ContentId == tvDbId && x.EpisodeNumber == ep.EpisodeNumber && x.SeasonNumber == ep.SeasonNumber)) - { - continue; - } - - itemsToReturn.Add(ep); - } - - return itemsToReturn; - } - - private HashSet FilterJellyfinEpisodes(IEnumerable source, IEnumerable recentlyAdded) - { - var itemsToReturn = new HashSet(); + var itemsToReturn = new HashSet(); foreach (var ep in source.Where(x => x.Series.HasTvDb)) { var tvDbId = StringHelper.IntParseLinq(ep.Series.TvDbId); @@ -564,17 +484,14 @@ private NotificationMessageContent ParseTemplate(NotificationTemplates template, return resolver.ParseMessage(template, curlys); } - private async Task BuildHtml(IQueryable plexContentToSend, IQueryable embyContentToSend, IQueryable jellyfinContentToSend, - HashSet plexEpisodes, HashSet embyEp, HashSet jellyfinEp, HashSet albums, NewsletterSettings settings, EmbySettings embySettings, JellyfinSettings jellyfinSettings, + private async Task BuildHtml(ICollection> contentToSend, + ICollection> episodes, HashSet albums, NewsletterSettings settings, EmbySettings embySettings, JellyfinSettings jellyfinSettings, PlexSettings plexSettings) { var ombiSettings = await _ombiSettings.GetSettingsAsync(); var sb = new StringBuilder(); - var plexMovies = plexContentToSend.Where(x => x.Type == MediaType.Movie); - var embyMovies = embyContentToSend.Where(x => x.Type == MediaType.Movie); - var jellyfinMovies = jellyfinContentToSend.Where(x => x.Type == MediaType.Movie); - if ((plexMovies.Any() || embyMovies.Any() || jellyfinMovies.Any()) && !settings.DisableMovies) + if (!settings.DisableMovies) { sb.Append("

New Movies



"); sb.Append( @@ -583,21 +500,10 @@ private async Task BuildHtml(IQueryable plexContentTo sb.Append(""); sb.Append(""); sb.Append(""); - if (plexSettings.Enable) - { - await ProcessPlexMovies(plexMovies, sb, ombiSettings.DefaultLanguageCode, plexSettings.Servers.FirstOrDefault().ServerHostname ?? string.Empty); - } - - if (embySettings.Enable) - { - await ProcessEmbyMovies(embyMovies, sb, ombiSettings.DefaultLanguageCode, embySettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty); - } - - if (jellyfinSettings.Enable) + foreach (var mediaServerContent in contentToSend) { - await ProcessJellyfinMovies(jellyfinMovies, sb, ombiSettings.DefaultLanguageCode, jellyfinSettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty); + await ProcessMovies(mediaServerContent, sb, ombiSettings.DefaultLanguageCode, /*plexSettings.Servers?.FirstOrDefault()?.ServerHostname ?? */ string.Empty); } - sb.Append(""); sb.Append("
"); sb.Append(""); @@ -605,7 +511,7 @@ private async Task BuildHtml(IQueryable plexContentTo sb.Append(""); } - if ((plexEpisodes.Any() || embyEp.Any() || jellyfinEp.Any()) && !settings.DisableTv) + if (!settings.DisableTv) { sb.Append("

New TV



"); sb.Append( @@ -614,21 +520,10 @@ private async Task BuildHtml(IQueryable plexContentTo sb.Append(""); sb.Append(""); sb.Append(""); - if (plexSettings.Enable) + foreach (var mediaServerContent in episodes) { - await ProcessPlexTv(plexEpisodes, sb, ombiSettings.DefaultLanguageCode, plexSettings.Servers.FirstOrDefault().ServerHostname ?? string.Empty); + await ProcessTv(mediaServerContent, sb, ombiSettings.DefaultLanguageCode, /* plexSettings.Servers.FirstOrDefault()?.ServerHostname ?? */ string.Empty); } - - if (embySettings.Enable) - { - await ProcessEmbyTv(embyEp, sb, ombiSettings.DefaultLanguageCode, embySettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty); - } - - if (jellyfinSettings.Enable) - { - await ProcessJellyfinTv(jellyfinEp, sb, ombiSettings.DefaultLanguageCode, jellyfinSettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty); - } - sb.Append(""); sb.Append("
"); sb.Append(""); @@ -657,7 +552,7 @@ private async Task BuildHtml(IQueryable plexContentTo return sb.ToString(); } - private async Task ProcessPlexMovies(IQueryable plexContentToSend, StringBuilder sb, string defaultLanguageCode, string mediaServerUrl) + private async Task ProcessMovies(IQueryable plexContentToSend, StringBuilder sb, string defaultLanguageCode, string mediaServerUrl) { int count = 0; var ordered = plexContentToSend.OrderByDescending(x => x.AddedAt); @@ -681,7 +576,7 @@ private async Task ProcessPlexMovies(IQueryable plexContentTo } catch (Exception e) { - _log.LogError(e, "Error when Processing Plex Movies {0}", info.Title); + _log.LogError(e, "Error when Processing Movies {0}", info.Title); } finally { @@ -731,112 +626,6 @@ private async Task ProcessAlbums(HashSet albumsToSend, StringB } } - private async Task ProcessEmbyMovies(IQueryable embyContent, StringBuilder sb, string defaultLangaugeCode, string customUrl) - { - int count = 0; - var ordered = embyContent.OrderByDescending(x => x.AddedAt); - foreach (var content in ordered) - { - var theMovieDbId = content.TheMovieDbId; - if (!content.TheMovieDbId.HasValue()) - { - var imdbId = content.ImdbId; - var findResult = await _movieApi.Find(imdbId, ExternalSource.imdb_id); - var result = findResult.movie_results?.FirstOrDefault(); - if (result == null) - { - continue; - } - - theMovieDbId = result.id.ToString(); - } - - var mediaurl = content.Url; - if (customUrl.HasValue()) - { - mediaurl = customUrl; - } - var info = await _movieApi.GetMovieInformationWithExtraInfo(StringHelper.IntParseLinq(theMovieDbId), defaultLangaugeCode); - if (info == null) - { - continue; - } - try - { - CreateMovieHtmlContent(sb, info, mediaurl); - count += 1; - } - catch (Exception e) - { - _log.LogError(e, "Error when processing Emby Movies {0}", info.Title); - } - finally - { - EndLoopHtml(sb); - } - - if (count == 2) - { - count = 0; - sb.Append(""); - sb.Append(""); - } - } - } - - private async Task ProcessJellyfinMovies(IQueryable embyContent, StringBuilder sb, string defaultLangaugeCode, string customUrl) - { - int count = 0; - var ordered = embyContent.OrderByDescending(x => x.AddedAt); - foreach (var content in ordered) - { - var theMovieDbId = content.TheMovieDbId; - if (!content.TheMovieDbId.HasValue()) - { - var imdbId = content.ImdbId; - var findResult = await _movieApi.Find(imdbId, ExternalSource.imdb_id); - var result = findResult.movie_results?.FirstOrDefault(); - if (result == null) - { - continue; - } - - theMovieDbId = result.id.ToString(); - } - - var mediaurl = content.Url; - if (customUrl.HasValue()) - { - mediaurl = customUrl; - } - var info = await _movieApi.GetMovieInformationWithExtraInfo(StringHelper.IntParseLinq(theMovieDbId), defaultLangaugeCode); - if (info == null) - { - continue; - } - try - { - CreateMovieHtmlContent(sb, info, mediaurl); - count += 1; - } - catch (Exception e) - { - _log.LogError(e, "Error when processing Jellyfin Movies {0}", info.Title); - } - finally - { - EndLoopHtml(sb); - } - - if (count == 2) - { - count = 0; - sb.Append(""); - sb.Append(""); - } - } - } - private void CreateMovieHtmlContent(StringBuilder sb, MovieResponseDto info, string mediaurl) { AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w1280/{info.BackdropPath}"); @@ -909,24 +698,23 @@ private void CreateAlbumHtmlContent(StringBuilder sb, AlbumLookup info) AddGenres(sb, $"Type: {info.albumType}"); } - private async Task ProcessPlexTv(HashSet plexContent, StringBuilder sb, string languageCode, string serverHostname) + private async Task ProcessTv(IEnumerable episodes, StringBuilder sb, string languageCode, string serverHostname) { - var series = new List(); - foreach (var plexEpisode in plexContent) + var series = new List(); + foreach (var episode in episodes) { - var alreadyAdded = series.FirstOrDefault(x => x.Key == plexEpisode.PlexSeries.Key); - if (alreadyAdded != null) + var existingSeries = episode.SeriesIsIn(series); + if (existingSeries != null) { - var episodeExists = alreadyAdded.PlexEpisodes.Any(x => x.Key == plexEpisode.Key); - if (!episodeExists) + if (!episode.IsIn(existingSeries)) { - alreadyAdded.Episodes.Add(plexEpisode); + existingSeries.Episodes.Add(episode); } } else { - plexEpisode.Series.Episodes = new List { plexEpisode }; - series.Add(plexEpisode.PlexSeries); + episode.Series.Episodes = new List { episode }; + series.Add(episode.Series); } } @@ -1035,214 +823,6 @@ private async Task ProcessPlexTv(HashSet plexContent, StringBuilder } } - - - private async Task ProcessEmbyTv(HashSet embyContent, StringBuilder sb, string languageCode, string serverUrl) - { - var series = new List(); - foreach (var episode in embyContent) - { - var alreadyAdded = series.FirstOrDefault(x => x.EmbyId == episode.EmbySeries.EmbyId); - if (alreadyAdded != null) - { - alreadyAdded.Episodes.Add(episode); - } - else - { - episode.Series.Episodes = new List - { - episode - }; - series.Add(episode.EmbySeries); - } - } - - int count = 0; - var orderedTv = series.OrderByDescending(x => x.AddedAt); - foreach (var t in orderedTv) - { - if (!t.TvDbId.HasValue()) - { - continue; - } - - int.TryParse(t.TvDbId, out var tvdbId); - var info = await _tvApi.ShowLookupByTheTvDbId(tvdbId); - if (info == null) - { - continue; - } - - try - { - var banner = info.image?.original; - if (!string.IsNullOrEmpty(banner)) - { - banner = banner.ToHttpsUrl(); // Always use the Https banners - } - - var tvInfo = await _movieApi.GetTVInfo(t.TheMovieDbId, languageCode); - if (tvInfo != null && tvInfo.backdrop_path.HasValue()) - { - - AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w500{tvInfo.backdrop_path}"); - } - else - { - AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w1280/"); - } - AddPosterInsideTable(sb, banner); - AddMediaServerUrl(sb, serverUrl.HasValue() ? serverUrl : t.Url, banner); - AddInfoTable(sb); - - AddTvTitle(sb, info, tvInfo); - - // Group by the season number - var results = t.Episodes?.GroupBy(p => p.SeasonNumber, - (key, g) => new - { - SeasonNumber = key, - Episodes = g.ToList(), - EpisodeAirDate = tvInfo?.seasons?.Where(x => x.season_number == key)?.Select(x => x.air_date).FirstOrDefault() - } - ); - - // Group the episodes - var finalsb = new StringBuilder(); - foreach (var epInformation in results.OrderBy(x => x.SeasonNumber)) - { - var orderedEpisodes = epInformation.Episodes.OrderBy(x => x.EpisodeNumber).ToList(); - var episodeString = StringHelper.BuildEpisodeList(orderedEpisodes.Select(x => x.EpisodeNumber)); - var episodeAirDate = epInformation.EpisodeAirDate; - finalsb.Append($"Season: {epInformation.SeasonNumber} - Episodes: {episodeString} {episodeAirDate}"); - finalsb.Append("
"); - } - - AddTvEpisodesSummaryGenres(sb, finalsb.ToString(), tvInfo); - - } - catch (Exception e) - { - _log.LogError(e, "Error when processing Emby TV {0}", t.Title); - } - finally - { - EndLoopHtml(sb); - count += 1; - } - - if (count == 2) - { - count = 0; - sb.Append(""); - sb.Append(""); - } - } - } - - private async Task ProcessJellyfinTv(HashSet jellyfinContent, StringBuilder sb, string languageCode, string serverUrl) - { - var series = new List(); - foreach (var episode in jellyfinContent) - { - var alreadyAdded = series.FirstOrDefault(x => x.JellyfinId == episode.JellyfinSeries.JellyfinId); - if (alreadyAdded != null) - { - alreadyAdded.Episodes.Add(episode); - } - else - { - episode.Series.Episodes = new List - { - episode - }; - series.Add(episode.JellyfinSeries); - } - } - - int count = 0; - var orderedTv = series.OrderByDescending(x => x.AddedAt); - foreach (var t in orderedTv) - { - if (!t.TvDbId.HasValue()) - { - continue; - } - - int.TryParse(t.TvDbId, out var tvdbId); - var info = await _tvApi.ShowLookupByTheTvDbId(tvdbId); - if (info == null) - { - continue; - } - - try - { - var banner = info.image?.original; - if (!string.IsNullOrEmpty(banner)) - { - banner = banner.ToHttpsUrl(); // Always use the Https banners - } - - var tvInfo = await _movieApi.GetTVInfo(t.TheMovieDbId, languageCode); - if (tvInfo != null && tvInfo.backdrop_path.HasValue()) - { - - AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w500{tvInfo.backdrop_path}"); - } - else - { - AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w1280/"); - } - AddPosterInsideTable(sb, banner); - AddMediaServerUrl(sb, serverUrl.HasValue() ? serverUrl : t.Url, banner); - AddInfoTable(sb); - - AddTvTitle(sb, info, tvInfo); - - // Group by the season number - var results = t.Episodes?.GroupBy(p => p.SeasonNumber, - (key, g) => new - { - SeasonNumber = key, - Episodes = g.ToList(), - EpisodeAirDate = tvInfo?.seasons?.Where(x => x.season_number == key)?.Select(x => x.air_date).FirstOrDefault() - } - ); - - // Group the episodes - var finalsb = new StringBuilder(); - foreach (var epInformation in results.OrderBy(x => x.SeasonNumber)) - { - var orderedEpisodes = epInformation.Episodes.OrderBy(x => x.EpisodeNumber).ToList(); - var episodeString = StringHelper.BuildEpisodeList(orderedEpisodes.Select(x => x.EpisodeNumber)); - var episodeAirDate = epInformation.EpisodeAirDate; - finalsb.Append($"Season: {epInformation.SeasonNumber} - Episodes: {episodeString} {episodeAirDate}"); - finalsb.Append("
"); - } - - AddTvEpisodesSummaryGenres(sb, finalsb.ToString(), tvInfo); - - } - catch (Exception e) - { - _log.LogError(e, "Error when processing Jellyfin TV {0}", t.Title); - } - finally - { - EndLoopHtml(sb); - count += 1; - } - - if (count == 2) - { - count = 0; - sb.Append(""); - sb.Append(""); - } - } - } - private void AddTvTitle(StringBuilder sb, Api.TvMaze.Models.TvMazeShow info, TvInfo tvInfo) { var title = ""; diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs index 822a0f197..74dc4aa96 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs @@ -86,7 +86,7 @@ private async Task ProcessTv(List tv) var tvDbId = child.ParentRequest.TvDbId; var imdbId = child.ParentRequest.ImdbId; - IQueryable seriesEpisodes = null; + IQueryable seriesEpisodes = null; if (useImdb) { seriesEpisodes = plexEpisodes.Where(x => x.Series.ImdbId == imdbId.ToString()); @@ -105,8 +105,7 @@ private async Task ProcessTv(List tv) { // Let's try and match the series by name seriesEpisodes = plexEpisodes.Where(x => - x.Series.Title == child.Title && - x.PlexSeries.ReleaseYear == child.ParentRequest.ReleaseDate.Year.ToString()); + x.Series.Title == child.Title); } diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index c36bfa1aa..637d7591d 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -226,7 +226,7 @@ private async Task ProcessServer(PlexServers servers, bool rec await Repo.SaveChangesAsync(); if (content.Metadata != null) { - var episodesAdded = await EpisodeSync.ProcessEpsiodes(content.Metadata, allEps); + var episodesAdded = await EpisodeSync.ProcessEpsiodes(content.Metadata, (IQueryable)allEps); episodesProcessed.AddRange(episodesAdded.Select(x => x.Id)); } } @@ -463,7 +463,7 @@ private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet x.GrandparentKey == oldKey); + var episodeToChange = Repo.GetAllEpisodes().Cast().Where(x => x.GrandparentKey == oldKey); if (episodeToChange.Any()) { foreach (var e in episodeToChange) diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs index 6fbbb7612..ad36cb6ea 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs @@ -113,7 +113,7 @@ private async Task GetEpisodes(PlexServers settings, Directory section) { var currentPosition = 0; var resultCount = settings.EpisodeBatchSize == 0 ? 150 : settings.EpisodeBatchSize; - var currentEpisodes = _repo.GetAllEpisodes(); + var currentEpisodes = _repo.GetAllEpisodes().Cast(); 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}"); diff --git a/src/Ombi.Store/Entities/EmbyEpisode.cs b/src/Ombi.Store/Entities/EmbyEpisode.cs index 5b31fa3ac..1d2a03b46 100644 --- a/src/Ombi.Store/Entities/EmbyEpisode.cs +++ b/src/Ombi.Store/Entities/EmbyEpisode.cs @@ -26,8 +26,9 @@ #endregion using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; -using Microsoft.EntityFrameworkCore.Metadata; +using System.Linq; namespace Ombi.Store.Entities { @@ -50,5 +51,16 @@ public EmbyContent EmbySeries get => (EmbyContent)Series; set => Series = value; } + + public override IMediaServerContent SeriesIsIn(List content) + { + return content.Cast().FirstOrDefault( + x => x.EmbyId == this.EmbySeries.EmbyId); + } + public override bool IsIn(IMediaServerContent content) + { + return content.Episodes.Cast().Any(x => x.EmbyId == this.EmbyId); + } + } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/IMediaServerContent.cs b/src/Ombi.Store/Entities/IMediaServerContent.cs index 1eb7f7606..6b5efd595 100644 --- a/src/Ombi.Store/Entities/IMediaServerContent.cs +++ b/src/Ombi.Store/Entities/IMediaServerContent.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using Ombi.Store.Repository; namespace Ombi.Store.Entities { public interface IMediaServerContent { + public int Id { get; set; } public string Title { get; set; } public string ImdbId { get; set; } public string TvDbId { get; set; } @@ -42,6 +44,8 @@ public interface IMediaServerEpisode public IMediaServerContent Series { get; set; } + public IMediaServerContent SeriesIsIn(List content); + public bool IsIn(IMediaServerContent content); } public enum MediaType diff --git a/src/Ombi.Store/Entities/JellyfinEpisode.cs b/src/Ombi.Store/Entities/JellyfinEpisode.cs index cff3cf486..890cf3c2a 100644 --- a/src/Ombi.Store/Entities/JellyfinEpisode.cs +++ b/src/Ombi.Store/Entities/JellyfinEpisode.cs @@ -26,7 +26,9 @@ #endregion using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; using Microsoft.EntityFrameworkCore.Metadata; namespace Ombi.Store.Entities @@ -50,5 +52,15 @@ public JellyfinContent JellyfinSeries get => (JellyfinContent)Series; set => Series = value; } + + public override IMediaServerContent SeriesIsIn(List content) + { + return content.Cast().FirstOrDefault( + x => x.JellyfinId == this.JellyfinSeries.JellyfinId); + } + public override bool IsIn(IMediaServerContent content) + { + return content.Episodes.Cast().Any(x => x.JellyfinId == this.JellyfinId); + } } } diff --git a/src/Ombi.Store/Entities/MediaServerContent.cs b/src/Ombi.Store/Entities/MediaServerContent.cs index a1aee79c4..74220425c 100644 --- a/src/Ombi.Store/Entities/MediaServerContent.cs +++ b/src/Ombi.Store/Entities/MediaServerContent.cs @@ -35,5 +35,8 @@ public abstract class MediaServerEpisode: Entity, IMediaServerEpisode public string Title { get; set; } public IMediaServerContent Series { get; set; } + + public abstract IMediaServerContent SeriesIsIn(List content); + public abstract bool IsIn(IMediaServerContent content); } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/PlexEpisode.cs b/src/Ombi.Store/Entities/PlexEpisode.cs index 4c7e3300b..9d7ca87c8 100644 --- a/src/Ombi.Store/Entities/PlexEpisode.cs +++ b/src/Ombi.Store/Entities/PlexEpisode.cs @@ -1,4 +1,6 @@ -using System.ComponentModel.DataAnnotations.Schema; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; namespace Ombi.Store.Entities { @@ -20,5 +22,17 @@ public PlexServerContent PlexSeries get => (PlexServerContent)Series; set => Series = value; } + + public override IMediaServerContent SeriesIsIn(List content) + { + return content.Cast().FirstOrDefault( + x => x.Key == this.PlexSeries.Key); + } + + public override bool IsIn(IMediaServerContent content) + { + return content.Episodes.Cast().Any(x => x.Key == this.Key); + } + } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/EmbyContentRepository.cs b/src/Ombi.Store/Repository/EmbyContentRepository.cs index f8743e30f..7eb1e4e3f 100644 --- a/src/Ombi.Store/Repository/EmbyContentRepository.cs +++ b/src/Ombi.Store/Repository/EmbyContentRepository.cs @@ -69,20 +69,20 @@ public async Task GetByEmbyId(string embyId) return await Db.EmbyContent./*Include(x => x.Seasons).*/FirstOrDefaultAsync(x => x.EmbyId == embyId); } - public async Task Update(EmbyContent existingContent) + public async Task Update(IMediaServerContent existingContent) { - Db.EmbyContent.Update(existingContent); + Db.EmbyContent.Update((EmbyContent)existingContent); await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public IQueryable GetAllEpisodes() { return Db.EmbyEpisode.AsQueryable(); } - public async Task Add(EmbyEpisode content) + public async Task Add(IMediaServerEpisode content) { - await Db.EmbyEpisode.AddAsync(content); + await Db.EmbyEpisode.AddAsync((EmbyEpisode)content); await InternalSaveChanges(); return content; } @@ -91,15 +91,15 @@ public async Task GetEpisodeByEmbyId(string key) return await Db.EmbyEpisode.FirstOrDefaultAsync(x => x.EmbyId == key); } - public async Task AddRange(IEnumerable content) + public async Task AddRange(IEnumerable content) { - Db.EmbyEpisode.AddRange(content); + Db.EmbyEpisode.AddRange((EmbyEpisode)content); await InternalSaveChanges(); } - public void UpdateWithoutSave(EmbyContent existingContent) + public void UpdateWithoutSave(IMediaServerContent existingContent) { - Db.EmbyContent.Update(existingContent); + Db.EmbyContent.Update((EmbyContent)existingContent); } } diff --git a/src/Ombi.Store/Repository/IMediaServerContentRepository.cs b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs index 1abb25b66..ef4ad7a55 100644 --- a/src/Ombi.Store/Repository/IMediaServerContentRepository.cs +++ b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs @@ -5,13 +5,8 @@ namespace Ombi.Store.Repository { - public interface IMediaServerContentRepository : IExternalRepository where Content : Entity + public interface IMediaServerContentRepository : IExternalRepository, IMediaServerContentRepositoryLight + where Content : Entity { - Task Update(Content existingContent); - IQueryable GetAllEpisodes(); - Task Add(Episode content); - Task AddRange(IEnumerable content); - - void UpdateWithoutSave(Content existingContent); } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs b/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs new file mode 100644 index 000000000..1eb69e10c --- /dev/null +++ b/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ombi.Store.Entities; + +namespace Ombi.Store.Repository +{ + public interface IMediaServerContentRepositoryLight + { + Task Update(IMediaServerContent existingContent); + IQueryable GetAllEpisodes(); + Task Add(IMediaServerEpisode content); + Task AddRange(IEnumerable content); + void UpdateWithoutSave(IMediaServerContent existingContent); + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Repository/JellyfinContentRepository.cs b/src/Ombi.Store/Repository/JellyfinContentRepository.cs index 2b84adb00..5b09cf84a 100644 --- a/src/Ombi.Store/Repository/JellyfinContentRepository.cs +++ b/src/Ombi.Store/Repository/JellyfinContentRepository.cs @@ -69,20 +69,20 @@ public async Task GetByJellyfinId(string jellyfinId) return await Db.JellyfinContent./*Include(x => x.Seasons).*/FirstOrDefaultAsync(x => x.JellyfinId == jellyfinId); } - public async Task Update(JellyfinContent existingContent) + public async Task Update(IMediaServerContent existingContent) { - Db.JellyfinContent.Update(existingContent); + Db.JellyfinContent.Update((JellyfinContent)existingContent); await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public IQueryable GetAllEpisodes() { return Db.JellyfinEpisode.AsQueryable(); } - public async Task Add(JellyfinEpisode content) + public async Task Add(IMediaServerEpisode content) { - await Db.JellyfinEpisode.AddAsync(content); + await Db.JellyfinEpisode.AddAsync((JellyfinEpisode)content); await InternalSaveChanges(); return content; } @@ -91,15 +91,15 @@ public async Task GetEpisodeByJellyfinId(string key) return await Db.JellyfinEpisode.FirstOrDefaultAsync(x => x.JellyfinId == key); } - public async Task AddRange(IEnumerable content) + public async Task AddRange(IEnumerable content) { - Db.JellyfinEpisode.AddRange(content); + Db.JellyfinEpisode.AddRange((JellyfinEpisode)content); await InternalSaveChanges(); } - public void UpdateWithoutSave(JellyfinContent existingContent) + public void UpdateWithoutSave(IMediaServerContent existingContent) { - Db.JellyfinContent.Update(existingContent); + Db.JellyfinContent.Update((JellyfinContent)existingContent); } } diff --git a/src/Ombi.Store/Repository/PlexContentRepository.cs b/src/Ombi.Store/Repository/PlexContentRepository.cs index 917a44b55..61139d4c6 100644 --- a/src/Ombi.Store/Repository/PlexContentRepository.cs +++ b/src/Ombi.Store/Repository/PlexContentRepository.cs @@ -114,14 +114,14 @@ public async Task GetFirstContentByCustom(Expression existingContent) @@ -130,7 +130,7 @@ public async Task UpdateRange(IEnumerable existingContent) await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public IQueryable GetAllEpisodes() { return Db.PlexEpisode.Include(x => x.Series).AsQueryable(); } @@ -145,9 +145,9 @@ public void DeleteWithoutSave(PlexEpisode content) Db.PlexEpisode.Remove(content); } - public async Task Add(PlexEpisode content) + public async Task Add(IMediaServerEpisode content) { - await Db.PlexEpisode.AddAsync(content); + await Db.PlexEpisode.AddAsync((PlexEpisode)content); await InternalSaveChanges(); return content; } @@ -162,9 +162,9 @@ public async Task GetEpisodeByKey(int key) { return await Db.PlexEpisode.FirstOrDefaultAsync(x => x.Key == key); } - public async Task AddRange(IEnumerable content) + public async Task AddRange(IEnumerable content) { - Db.PlexEpisode.AddRange(content); + Db.PlexEpisode.AddRange((PlexEpisode)content); await InternalSaveChanges(); } } From 94c341098f3211ffc7793513824133192c7b7b3e Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Fri, 14 Jan 2022 12:58:45 +0100 Subject: [PATCH 05/21] Minor code clean up --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 92a8019be..249dbb693 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -124,14 +124,14 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) var customization = await _customizationSettings.GetSettingsAsync(); - // MOVIES var plexContent = (IQueryable)_plex.GetAll().Include(x => x.Episodes).AsNoTracking(); var embyContent = (IQueryable)_emby.GetAll().Include(x => x.Episodes).AsNoTracking(); var jellyfinContent = (IQueryable)_jellyfin.GetAll().Include(x => x.Episodes).AsNoTracking(); - var plexContentMoviesToSend = await getMoviesContent(plexContent, RecentlyAddedType.Plex); - var embyContentMoviesToSend = await getMoviesContent(embyContent, RecentlyAddedType.Emby); - var jellyfinContentMoviesToSend = await getMoviesContent(jellyfinContent, RecentlyAddedType.Jellyfin); + // MOVIES + var plexContentMoviesToSend = await GetMoviesContent(plexContent, RecentlyAddedType.Plex); + var embyContentMoviesToSend = await GetMoviesContent(embyContent, RecentlyAddedType.Emby); + var jellyfinContentMoviesToSend = await GetMoviesContent(jellyfinContent, RecentlyAddedType.Jellyfin); // MUSIC var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable); @@ -383,7 +383,7 @@ private void GetRecentlyAddedMoviesData(List addedLog, out Has addedAlbumLogIds = lidarrParent != null && lidarrParent.Any() ? (lidarrParent?.Select(x => x.AlbumId)?.ToHashSet() ?? new HashSet()) : new HashSet(); } - private async Task> getMoviesContent(IQueryable content, RecentlyAddedType recentlyAddedType) + private async Task> GetMoviesContent(IQueryable content, RecentlyAddedType recentlyAddedType) { var localDataset = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); // Filter out the ones that we haven't sent yet From cfe5797fdce2eb2c4c8c801f2cd0816a057b03a6 Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Sat, 15 Jan 2022 18:10:31 +0100 Subject: [PATCH 06/21] Attempt at abstracting repositories (WIP) --- .../Jobs/Emby/EmbyContentSync.cs | 4 +- .../Jobs/Jellyfin/JellyfinContentSync.cs | 4 +- .../Jobs/Ombi/HtmlTemplateGenerator.cs | 17 +- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 198 ++++++++---------- .../Jobs/Plex/PlexContentSync.cs | 6 +- src/Ombi.Store/Entities/Entity.cs | 2 +- src/Ombi.Store/Entities/IEntity.cs | 10 + .../Entities/IMediaServerContent.cs | 4 +- src/Ombi.Store/Entities/MediaServerContent.cs | 4 + .../Repository/EmbyContentRepository.cs | 17 +- .../Repository/IEmbyContentRepository.cs | 2 +- .../Repository/IExternalRepository.cs | 3 +- .../Repository/IJellyfinContentRepository.cs | 2 +- .../IMediaServerContentRepository.cs | 4 +- .../IMediaServerContentRepositoryLight.cs | 14 ++ .../Repository/IPlexContentRepository.cs | 2 +- src/Ombi.Store/Repository/IRepository.cs | 3 +- .../Repository/JellyfinContentRepository.cs | 19 +- .../Repository/MediaServerRepository.cs | 30 +++ .../Repository/PlexContentRepository.cs | 19 +- 20 files changed, 199 insertions(+), 165 deletions(-) create mode 100644 src/Ombi.Store/Entities/IEntity.cs create mode 100644 src/Ombi.Store/Repository/MediaServerRepository.cs diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs index dd9be69e0..490b40bf6 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs @@ -168,7 +168,8 @@ private async Task ProcessTv(EmbyServers server, bool recentlyAdded, string pare Type = MediaType.Series, EmbyId = tvShow.Id, Url = EmbyHelper.GetEmbyMediaUrl(tvShow.Id, server?.ServerId, server.ServerHostname), - AddedAt = DateTime.UtcNow + AddedAt = DateTime.UtcNow, + Repository = _repo }); } else @@ -259,6 +260,7 @@ private async Task ProcessMovies(EmbyMovie movieInfo, ICollection c EmbyId = movieInfo.Id, Url = EmbyHelper.GetEmbyMediaUrl(movieInfo.Id, server?.ServerId, server.ServerHostname), AddedAt = DateTime.UtcNow, + Repository = _repo }); } else diff --git a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs index 8906e3a60..c9399f521 100644 --- a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs @@ -146,7 +146,8 @@ private async Task ProcessTv(JellyfinServers server, string parentId = default) Type = MediaType.Series, JellyfinId = tvShow.Id, Url = JellyfinHelper.GetJellyfinMediaUrl(tvShow.Id, server?.ServerId, server.ServerHostname), - AddedAt = DateTime.UtcNow + AddedAt = DateTime.UtcNow, + Repository = _repo }); } else @@ -227,6 +228,7 @@ private async Task ProcessMovies(JellyfinMovie movieInfo, ICollection"); sb.AppendFormat("", url); @@ -14,14 +15,14 @@ protected virtual void AddBackgroundInsideTable(StringBuilder sb, string url) sb.Append("
"); } - protected virtual void AddPosterInsideTable(StringBuilder sb, string url) + protected virtual void AddPosterInsideTable(string url) { sb.Append(""); sb.Append(""); @@ -552,7 +533,7 @@ private async Task BuildHtml(ICollection return sb.ToString(); } - private async Task ProcessMovies(IQueryable plexContentToSend, StringBuilder sb, string defaultLanguageCode, string mediaServerUrl) + private async Task ProcessMovies(IQueryable plexContentToSend, string defaultLanguageCode, string mediaServerUrl) { int count = 0; var ordered = plexContentToSend.OrderByDescending(x => x.AddedAt); @@ -571,7 +552,7 @@ private async Task ProcessMovies(IQueryable plexContentToSe } try { - CreateMovieHtmlContent(sb, info, mediaurl); + CreateMovieHtmlContent(info, mediaurl); count += 1; } catch (Exception e) @@ -580,7 +561,7 @@ private async Task ProcessMovies(IQueryable plexContentToSe } finally { - EndLoopHtml(sb); + EndLoopHtml(); } if (count == 2) @@ -591,7 +572,7 @@ private async Task ProcessMovies(IQueryable plexContentToSe } } } - private async Task ProcessAlbums(HashSet albumsToSend, StringBuilder sb) + private async Task ProcessAlbums(HashSet albumsToSend) { var settings = await _lidarrSettings.GetSettingsAsync(); int count = 0; @@ -605,7 +586,7 @@ private async Task ProcessAlbums(HashSet albumsToSend, StringB } try { - CreateAlbumHtmlContent(sb, info); + CreateAlbumHtmlContent(info); count += 1; } catch (Exception e) @@ -614,7 +595,7 @@ private async Task ProcessAlbums(HashSet albumsToSend, StringB } finally { - EndLoopHtml(sb); + EndLoopHtml(); } if (count == 2) @@ -626,13 +607,13 @@ private async Task ProcessAlbums(HashSet albumsToSend, StringB } } - private void CreateMovieHtmlContent(StringBuilder sb, MovieResponseDto info, string mediaurl) + private void CreateMovieHtmlContent(MovieResponseDto info, string mediaurl) { - AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w1280/{info.BackdropPath}"); - AddPosterInsideTable(sb, $"https://image.tmdb.org/t/p/original{info.PosterPath}"); + AddBackgroundInsideTable($"https://image.tmdb.org/t/p/w1280/{info.BackdropPath}"); + AddPosterInsideTable($"https://image.tmdb.org/t/p/original{info.PosterPath}"); - AddMediaServerUrl(sb, mediaurl, $"https://image.tmdb.org/t/p/original{info.PosterPath}"); - AddInfoTable(sb); + AddMediaServerUrl(mediaurl, $"https://image.tmdb.org/t/p/original{info.PosterPath}"); + AddInfoTable(); var releaseDate = string.Empty; try @@ -646,7 +627,7 @@ private void CreateMovieHtmlContent(StringBuilder sb, MovieResponseDto info, str // Swallow, couldn't parse the date } - AddTitle(sb, $"https://www.imdb.com/title/{info.ImdbId}/", $"{info.Title} {releaseDate}"); + AddTitle($"https://www.imdb.com/title/{info.ImdbId}/", $"{info.Title} {releaseDate}"); var summary = info.Overview; if (summary.Length > 280) @@ -654,16 +635,15 @@ private void CreateMovieHtmlContent(StringBuilder sb, MovieResponseDto info, str summary = summary.Remove(280); summary = summary + "...

"; } - AddParagraph(sb, summary); + AddParagraph(summary); if (info.Genres.Any()) { - AddGenres(sb, - $"Genres: {string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray())}"); + AddGenres($"Genres: {string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray())}"); } } - private void CreateAlbumHtmlContent(StringBuilder sb, AlbumLookup info) + private void CreateAlbumHtmlContent(AlbumLookup info) { var cover = info.images .FirstOrDefault(x => x.coverType.Equals("cover", StringComparison.InvariantCultureIgnoreCase))?.url; @@ -671,21 +651,21 @@ private void CreateAlbumHtmlContent(StringBuilder sb, AlbumLookup info) { cover = info.remoteCover; } - AddBackgroundInsideTable(sb, cover); + AddBackgroundInsideTable(cover); var disk = info.images .FirstOrDefault(x => x.coverType.Equals("disc", StringComparison.InvariantCultureIgnoreCase))?.url; if (disk.IsNullOrEmpty()) { disk = info.remoteCover; } - AddPosterInsideTable(sb, disk); + AddPosterInsideTable(disk); - AddMediaServerUrl(sb, string.Empty, string.Empty); - AddInfoTable(sb); + AddMediaServerUrl(string.Empty, string.Empty); + AddInfoTable(); var releaseDate = $"({info.releaseDate.Year})"; - AddTitle(sb, string.Empty, $"{info.title} {releaseDate}"); + AddTitle(string.Empty, $"{info.title} {releaseDate}"); var summary = info.artist?.artistName ?? string.Empty; if (summary.Length > 280) @@ -693,12 +673,12 @@ private void CreateAlbumHtmlContent(StringBuilder sb, AlbumLookup info) summary = summary.Remove(280); summary = summary + "...

"; } - AddParagraph(sb, summary); + AddParagraph(summary); - AddGenres(sb, $"Type: {info.albumType}"); + AddGenres($"Type: {info.albumType}"); } - private async Task ProcessTv(IEnumerable episodes, StringBuilder sb, string languageCode, string serverHostname) + private async Task ProcessTv(IEnumerable episodes, string languageCode, string serverHostname) { var series = new List(); foreach (var episode in episodes) @@ -768,17 +748,17 @@ private async Task ProcessTv(IEnumerable episodes, StringBu if (tvInfo != null && tvInfo.backdrop_path.HasValue()) { - AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w500{tvInfo.backdrop_path}"); + AddBackgroundInsideTable($"https://image.tmdb.org/t/p/w500{tvInfo.backdrop_path}"); } else { - AddBackgroundInsideTable(sb, $"https://image.tmdb.org/t/p/w1280/"); + AddBackgroundInsideTable($"https://image.tmdb.org/t/p/w1280/"); } - AddPosterInsideTable(sb, banner); - AddMediaServerUrl(sb, PlexHelper.BuildPlexMediaUrl(t.Url, serverHostname), banner); - AddInfoTable(sb); + AddPosterInsideTable(banner); + AddMediaServerUrl(PlexHelper.BuildPlexMediaUrl(t.Url, serverHostname), banner); + AddInfoTable(); - AddTvTitle(sb, info, tvInfo); + AddTvTitle(info, tvInfo); // Group by the season number var results = t.Episodes.GroupBy(p => p.SeasonNumber, @@ -801,7 +781,7 @@ private async Task ProcessTv(IEnumerable episodes, StringBu finalsb.Append("
"); } - AddTvEpisodesSummaryGenres(sb, finalsb.ToString(), tvInfo); + AddTvEpisodesSummaryGenres(finalsb.ToString(), tvInfo); } catch (Exception e) @@ -810,7 +790,7 @@ private async Task ProcessTv(IEnumerable episodes, StringBu } finally { - EndLoopHtml(sb); + EndLoopHtml(); count += 1; } @@ -823,7 +803,7 @@ private async Task ProcessTv(IEnumerable episodes, StringBu } } - private void AddTvTitle(StringBuilder sb, Api.TvMaze.Models.TvMazeShow info, TvInfo tvInfo) + private void AddTvTitle(Api.TvMaze.Models.TvMazeShow info, TvInfo tvInfo) { var title = ""; if (!String.IsNullOrEmpty(info.premiered) && info.premiered.Length > 4) @@ -834,10 +814,10 @@ private void AddTvTitle(StringBuilder sb, Api.TvMaze.Models.TvMazeShow info, TvI { title = $"{tvInfo.name}"; } - AddTitle(sb, $"https://www.imdb.com/title/{info.externals.imdb}/", title); + AddTitle($"https://www.imdb.com/title/{info.externals.imdb}/", title); } - private void AddTvEpisodesSummaryGenres(StringBuilder sb, string episodes, TvInfo tvInfo) + private void AddTvEpisodesSummaryGenres(string episodes, TvInfo tvInfo) { var summary = tvInfo.overview; if (summary.Length > 280) @@ -845,15 +825,15 @@ private void AddTvEpisodesSummaryGenres(StringBuilder sb, string episodes, TvInf summary = summary.Remove(280); summary = summary + "...

"; } - AddTvParagraph(sb, episodes, summary); + AddTvParagraph(episodes, summary); if (tvInfo.genres.Any()) { - AddGenres(sb, $"Genres: {string.Join(", ", tvInfo.genres.Select(x => x.name.ToString()).ToArray())}"); + AddGenres($"Genres: {string.Join(", ", tvInfo.genres.Select(x => x.name.ToString()).ToArray())}"); } } - private void EndLoopHtml(StringBuilder sb) + private void EndLoopHtml() { //NOTE: BR have to be in TD's as per html spec or it will be put outside of the table... //Source: http://stackoverflow.com/questions/6588638/phantom-br-tag-rendered-by-browsers-prior-to-table-tag diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index 637d7591d..c2a9d20bf 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -353,7 +353,8 @@ public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet Title = movie.title, Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey), Seasons = new List(), - Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty + Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty, + Repository = Repo }; if (providerIds.ImdbId.HasValue()) { @@ -556,7 +557,8 @@ private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet() + Seasons = new List(), + Repository = Repo }; await GetProviderIds(showMetadata, item); diff --git a/src/Ombi.Store/Entities/Entity.cs b/src/Ombi.Store/Entities/Entity.cs index 8e1cd2887..fac70de91 100644 --- a/src/Ombi.Store/Entities/Entity.cs +++ b/src/Ombi.Store/Entities/Entity.cs @@ -2,7 +2,7 @@ namespace Ombi.Store.Entities { - public abstract class Entity + public abstract class Entity: IEntity { [Key] public int Id { get; set; } diff --git a/src/Ombi.Store/Entities/IEntity.cs b/src/Ombi.Store/Entities/IEntity.cs new file mode 100644 index 000000000..004d214f1 --- /dev/null +++ b/src/Ombi.Store/Entities/IEntity.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace Ombi.Store.Entities +{ + public interface IEntity + { + [Key] + public int Id { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/IMediaServerContent.cs b/src/Ombi.Store/Entities/IMediaServerContent.cs index 6b5efd595..806602ee9 100644 --- a/src/Ombi.Store/Entities/IMediaServerContent.cs +++ b/src/Ombi.Store/Entities/IMediaServerContent.cs @@ -5,14 +5,14 @@ namespace Ombi.Store.Entities { - public interface IMediaServerContent + public interface IMediaServerContent: IEntity { - public int Id { get; set; } public string Title { get; set; } public string ImdbId { get; set; } public string TvDbId { get; set; } public string TheMovieDbId { get; set; } public MediaType Type { get; set; } + public IMediaServerContentRepositoryLight Repository { get; } public string Url { get; set; } diff --git a/src/Ombi.Store/Entities/MediaServerContent.cs b/src/Ombi.Store/Entities/MediaServerContent.cs index 74220425c..8055d0d95 100644 --- a/src/Ombi.Store/Entities/MediaServerContent.cs +++ b/src/Ombi.Store/Entities/MediaServerContent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using Ombi.Store.Repository; namespace Ombi.Store.Entities { @@ -26,6 +27,9 @@ public abstract class MediaServerContent: Entity, IMediaServerContent [NotMapped] public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); + + [NotMapped] //TODO: instantiate this variable upon read // something in ExternalContext.cs? + public IMediaServerContentRepositoryLight Repository { get; set; } } public abstract class MediaServerEpisode: Entity, IMediaServerEpisode diff --git a/src/Ombi.Store/Repository/EmbyContentRepository.cs b/src/Ombi.Store/Repository/EmbyContentRepository.cs index 7eb1e4e3f..adc260946 100644 --- a/src/Ombi.Store/Repository/EmbyContentRepository.cs +++ b/src/Ombi.Store/Repository/EmbyContentRepository.cs @@ -35,17 +35,13 @@ namespace Ombi.Store.Repository { - public class EmbyContentRepository : ExternalRepository, IEmbyContentRepository + public class EmbyContentRepository : MediaServerContentRepository, IEmbyContentRepository { public EmbyContentRepository(ExternalContext db):base(db) { - Db = db; } - private ExternalContext Db { get; } - - public async Task GetByImdbId(string imdbid) { return await Db.EmbyContent.FirstOrDefaultAsync(x => x.ImdbId == imdbid); @@ -69,18 +65,18 @@ public async Task GetByEmbyId(string embyId) return await Db.EmbyContent./*Include(x => x.Seasons).*/FirstOrDefaultAsync(x => x.EmbyId == embyId); } - public async Task Update(IMediaServerContent existingContent) + public override async Task Update(IMediaServerContent existingContent) { Db.EmbyContent.Update((EmbyContent)existingContent); await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public override IQueryable GetAllEpisodes() { return Db.EmbyEpisode.AsQueryable(); } - public async Task Add(IMediaServerEpisode content) + public override async Task Add(IMediaServerEpisode content) { await Db.EmbyEpisode.AddAsync((EmbyEpisode)content); await InternalSaveChanges(); @@ -91,16 +87,17 @@ public async Task GetEpisodeByEmbyId(string key) return await Db.EmbyEpisode.FirstOrDefaultAsync(x => x.EmbyId == key); } - public async Task AddRange(IEnumerable content) + public override async Task AddRange(IEnumerable content) { Db.EmbyEpisode.AddRange((EmbyEpisode)content); await InternalSaveChanges(); } - public void UpdateWithoutSave(IMediaServerContent existingContent) + public override void UpdateWithoutSave(IMediaServerContent existingContent) { Db.EmbyContent.Update((EmbyContent)existingContent); } + public override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Emby; } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IEmbyContentRepository.cs b/src/Ombi.Store/Repository/IEmbyContentRepository.cs index e3857cfb2..c171fef20 100644 --- a/src/Ombi.Store/Repository/IEmbyContentRepository.cs +++ b/src/Ombi.Store/Repository/IEmbyContentRepository.cs @@ -6,7 +6,7 @@ namespace Ombi.Store.Repository { - public interface IEmbyContentRepository : IMediaServerContentRepository + public interface IEmbyContentRepository : IMediaServerContentRepository { Task GetByEmbyId(string embyId); Task GetEpisodeByEmbyId(string key); diff --git a/src/Ombi.Store/Repository/IExternalRepository.cs b/src/Ombi.Store/Repository/IExternalRepository.cs index b22cb5ea8..ec7b27769 100644 --- a/src/Ombi.Store/Repository/IExternalRepository.cs +++ b/src/Ombi.Store/Repository/IExternalRepository.cs @@ -9,7 +9,7 @@ namespace Ombi.Store.Repository { - public interface IExternalRepository where T : Entity + public interface IExternalRepository where T : IEntity { Task Find(object key); IQueryable GetAll(); @@ -25,6 +25,5 @@ IIncludableQueryable Include( where TEntity : class; Task ExecuteSql(string sql); - DbSet _db { get; } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IJellyfinContentRepository.cs b/src/Ombi.Store/Repository/IJellyfinContentRepository.cs index eed242f0b..30efa1a17 100644 --- a/src/Ombi.Store/Repository/IJellyfinContentRepository.cs +++ b/src/Ombi.Store/Repository/IJellyfinContentRepository.cs @@ -6,7 +6,7 @@ namespace Ombi.Store.Repository { - public interface IJellyfinContentRepository : IMediaServerContentRepository + public interface IJellyfinContentRepository : IMediaServerContentRepository { Task GetByJellyfinId(string jellyfinId); Task GetEpisodeByJellyfinId(string key); diff --git a/src/Ombi.Store/Repository/IMediaServerContentRepository.cs b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs index ef4ad7a55..1f81a40ba 100644 --- a/src/Ombi.Store/Repository/IMediaServerContentRepository.cs +++ b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs @@ -5,8 +5,8 @@ namespace Ombi.Store.Repository { - public interface IMediaServerContentRepository : IExternalRepository, IMediaServerContentRepositoryLight - where Content : Entity + public interface IMediaServerContentRepository : IExternalRepository, IMediaServerContentRepositoryLight + where Content : IMediaServerContent { } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs b/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs index 1eb69e10c..1f1749ae8 100644 --- a/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs +++ b/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs @@ -5,9 +5,23 @@ namespace Ombi.Store.Repository { + // TOOD: this is a mess done to bypass the fact that + // I can't pass around IMediaServerContentRepository as a parameter + // because I want to pass it a generic IMediaServerContent as a 'type' + // and casting from concrete classes doesn't work due to my poor C# knowledge + + // My workaround so far has been to use this lightened interface, + // but the ever-growing number of wrapper methods for methods coming from IRepository + // is starting to smell (see implementing class MediaServerContentRepository). public interface IMediaServerContentRepositoryLight { + RecentlyAddedType RecentlyAddedType{ get; } Task Update(IMediaServerContent existingContent); + + // IQueryable GetAllContent(); + // Task FindContent(object key); + // Task SaveChangesAsync(); + IQueryable GetAllEpisodes(); Task Add(IMediaServerEpisode content); Task AddRange(IEnumerable content); diff --git a/src/Ombi.Store/Repository/IPlexContentRepository.cs b/src/Ombi.Store/Repository/IPlexContentRepository.cs index bbdd256de..8203959bc 100644 --- a/src/Ombi.Store/Repository/IPlexContentRepository.cs +++ b/src/Ombi.Store/Repository/IPlexContentRepository.cs @@ -8,7 +8,7 @@ namespace Ombi.Store.Repository { - public interface IPlexContentRepository : IMediaServerContentRepository + public interface IPlexContentRepository : IMediaServerContentRepository { Task ContentExists(string providerId); Task Get(string providerId, ProviderType type); diff --git a/src/Ombi.Store/Repository/IRepository.cs b/src/Ombi.Store/Repository/IRepository.cs index b93b07d45..a6142462f 100644 --- a/src/Ombi.Store/Repository/IRepository.cs +++ b/src/Ombi.Store/Repository/IRepository.cs @@ -10,7 +10,7 @@ namespace Ombi.Store.Repository { - public interface IRepository where T : Entity + public interface IRepository where T : IEntity { Task Find(object key); Task Find(object key, CancellationToken cancellationToken); @@ -27,6 +27,5 @@ IIncludableQueryable Include( where TEntity : class; Task ExecuteSql(string sql); - DbSet _db { get; } } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/JellyfinContentRepository.cs b/src/Ombi.Store/Repository/JellyfinContentRepository.cs index 5b09cf84a..800473248 100644 --- a/src/Ombi.Store/Repository/JellyfinContentRepository.cs +++ b/src/Ombi.Store/Repository/JellyfinContentRepository.cs @@ -35,17 +35,13 @@ namespace Ombi.Store.Repository { - public class JellyfinContentRepository : ExternalRepository, IJellyfinContentRepository + public class JellyfinContentRepository : MediaServerContentRepository, IJellyfinContentRepository { public JellyfinContentRepository(ExternalContext db):base(db) { - Db = db; } - private ExternalContext Db { get; } - - public async Task GetByImdbId(string imdbid) { return await Db.JellyfinContent.FirstOrDefaultAsync(x => x.ImdbId == imdbid); @@ -69,18 +65,18 @@ public async Task GetByJellyfinId(string jellyfinId) return await Db.JellyfinContent./*Include(x => x.Seasons).*/FirstOrDefaultAsync(x => x.JellyfinId == jellyfinId); } - public async Task Update(IMediaServerContent existingContent) + public override async Task Update(IMediaServerContent existingContent) { Db.JellyfinContent.Update((JellyfinContent)existingContent); await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public override IQueryable GetAllEpisodes() { return Db.JellyfinEpisode.AsQueryable(); } - public async Task Add(IMediaServerEpisode content) + public override async Task Add(IMediaServerEpisode content) { await Db.JellyfinEpisode.AddAsync((JellyfinEpisode)content); await InternalSaveChanges(); @@ -91,16 +87,17 @@ public async Task GetEpisodeByJellyfinId(string key) return await Db.JellyfinEpisode.FirstOrDefaultAsync(x => x.JellyfinId == key); } - public async Task AddRange(IEnumerable content) + public override async Task AddRange(IEnumerable content) { Db.JellyfinEpisode.AddRange((JellyfinEpisode)content); await InternalSaveChanges(); } - public void UpdateWithoutSave(IMediaServerContent existingContent) + public override void UpdateWithoutSave(IMediaServerContent existingContent) { Db.JellyfinContent.Update((JellyfinContent)existingContent); } - + + public override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Jellyfin; } } diff --git a/src/Ombi.Store/Repository/MediaServerRepository.cs b/src/Ombi.Store/Repository/MediaServerRepository.cs new file mode 100644 index 000000000..3fdc35ea8 --- /dev/null +++ b/src/Ombi.Store/Repository/MediaServerRepository.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Ombi.Store.Context; +using Ombi.Store.Entities; + +namespace Ombi.Store.Repository +{ + public abstract class MediaServerContentRepository : ExternalRepository, IMediaServerContentRepository where T : MediaServerContent + { + protected ExternalContext Db { get; } + public abstract RecentlyAddedType RecentlyAddedType { get; } + + public MediaServerContentRepository(ExternalContext db) : base(db) + { + Db = db; + } + + public abstract Task Update(IMediaServerContent existingContent); + + // TOOD: this smells: trying to wrap ExternalRepository methods in IMediaServerContentRepositoryLight for generic consumption + public IQueryable GetAllContent() => (IQueryable)GetAll(); + public async Task FindContent(object key) => (IMediaServerContent)await Find(key); + + public abstract IQueryable GetAllEpisodes(); + public abstract Task Add(IMediaServerEpisode content); + public abstract Task AddRange(IEnumerable content); + public abstract void UpdateWithoutSave(IMediaServerContent existingContent); + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Repository/PlexContentRepository.cs b/src/Ombi.Store/Repository/PlexContentRepository.cs index 61139d4c6..6429e679f 100644 --- a/src/Ombi.Store/Repository/PlexContentRepository.cs +++ b/src/Ombi.Store/Repository/PlexContentRepository.cs @@ -37,17 +37,13 @@ namespace Ombi.Store.Repository { - public class PlexServerContentRepository : ExternalRepository, IPlexContentRepository + public class PlexServerContentRepository : MediaServerContentRepository, IPlexContentRepository { - + public override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Plex; public PlexServerContentRepository(ExternalContext db) : base(db) { - Db = db; } - private ExternalContext Db { get; } - - public async Task ContentExists(string providerId) { var any = await Db.PlexServerContent.AnyAsync(x => x.ImdbId == providerId); @@ -114,12 +110,12 @@ public async Task GetFirstContentByCustom(Expression existingContent) await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public override IQueryable GetAllEpisodes() { return Db.PlexEpisode.Include(x => x.Series).AsQueryable(); } @@ -145,7 +141,7 @@ public void DeleteWithoutSave(PlexEpisode content) Db.PlexEpisode.Remove(content); } - public async Task Add(IMediaServerEpisode content) + public override async Task Add(IMediaServerEpisode content) { await Db.PlexEpisode.AddAsync((PlexEpisode)content); await InternalSaveChanges(); @@ -162,10 +158,11 @@ public async Task GetEpisodeByKey(int key) { return await Db.PlexEpisode.FirstOrDefaultAsync(x => x.Key == key); } - public async Task AddRange(IEnumerable content) + public override async Task AddRange(IEnumerable content) { Db.PlexEpisode.AddRange((PlexEpisode)content); await InternalSaveChanges(); } + } } \ No newline at end of file From a48650fcfb53e443d8ea2b84d7210351c9d84a6c Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sat, 15 Jan 2022 22:59:11 +0000 Subject: [PATCH 07/21] Fixed cast issue --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index f4bcc1a33..0e2313d5a 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -74,7 +74,7 @@ public NewsletterJob(IPlexContentRepository plex, IEmbyContentRepository emby, I _refreshMetadata = refreshMetadata; } - private readonly IPlexContentRepository _plex; + private readonly IMediaServerContentRepository _plex; private readonly IEmbyContentRepository _emby; private readonly IJellyfinContentRepository _jellyfin; private readonly IRepository _recentlyAddedLog; @@ -130,11 +130,9 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) // MOVIES var moviesContents = new List>(); - // these explicit casts won't work because: - // Unable to cast object of type 'PlexServerContentRepository' to type 'IMediaServerContentRepository`1[IMediaServerContent] - moviesContents.Add((await GetMoviesContent((IMediaServerContentRepository)_plex)).AsQueryable()); - moviesContents.Add((await GetMoviesContent((IMediaServerContentRepository)_emby)).AsQueryable()); - moviesContents.Add((await GetMoviesContent((IMediaServerContentRepository)_jellyfin)).AsQueryable()); + moviesContents.Add((await GetMoviesContent(_plex)).AsQueryable()); + moviesContents.Add((await GetMoviesContent(_emby)).AsQueryable()); + moviesContents.Add((await GetMoviesContent(_jellyfin)).AsQueryable()); // MUSIC var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable); @@ -363,9 +361,9 @@ private void GetRecentlyAddedMoviesData(List addedLog, out Has addedAlbumLogIds = lidarrParent != null && lidarrParent.Any() ? (lidarrParent?.Select(x => x.AlbumId)?.ToHashSet() ?? new HashSet()) : new HashSet(); } - private async Task> GetMoviesContent(IMediaServerContentRepository repository) + private async Task> GetMoviesContent(IMediaServerContentRepository repository) where T : class, IMediaServerContent { - var content = repository.GetAll().Include(x => x.Episodes).AsNoTracking(); + IQueryable content = repository.GetAll().Include(x => x.Episodes).AsNoTracking(); var localDataset = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); // Filter out the ones that we haven't sent yet var addedLog = _recentlyAddedLog.GetAll().ToList(); @@ -399,7 +397,7 @@ public static string GenerateUnsubscribeLink(string applicationUrl, string id) return b.ToString(); } - private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDb, IMediaServerContentRepository repository) + private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDb, IMediaServerContentRepository repository) where T : class, IMediaServerContent { foreach (var movie in needsMovieDb) { @@ -413,7 +411,7 @@ private async Task> GetMoviesWithoutId(HashSet return result.ToHashSet(); } - private async Task UpdateTheMovieDbId(IEnumerable content, IMediaServerContentRepository repository) + private async Task UpdateTheMovieDbId(IEnumerable content, IMediaServerContentRepository repository) where T : class, IMediaServerContent { foreach (var movie in content) { From 29213b073d4787fd3edf4b073888b0774b79ed3c Mon Sep 17 00:00:00 2001 From: tidusjar Date: Sat, 15 Jan 2022 23:00:11 +0000 Subject: [PATCH 08/21] Corrected the other properties --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 0e2313d5a..8f0b2315d 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -75,8 +75,8 @@ public NewsletterJob(IPlexContentRepository plex, IEmbyContentRepository emby, I } private readonly IMediaServerContentRepository _plex; - private readonly IEmbyContentRepository _emby; - private readonly IJellyfinContentRepository _jellyfin; + private readonly IMediaServerContentRepository _emby; + private readonly IMediaServerContentRepository _jellyfin; private readonly IRepository _recentlyAddedLog; private readonly IMovieDbApi _movieApi; private readonly ITvMazeApi _tvApi; From 9975315eecf40e2eb641062783ba04e142b8ba0a Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Sun, 16 Jan 2022 18:32:03 +0100 Subject: [PATCH 09/21] A step towards newsletter refactoring --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 291 ++++++++---------- .../Entities/IMediaServerContent.cs | 1 + src/Ombi.Store/Entities/MediaServerContent.cs | 4 + 3 files changed, 134 insertions(+), 162 deletions(-) diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 8f0b2315d..53ab15f00 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -1,18 +1,13 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; -using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -using MailKit; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using MimeKit; -using Ombi.Api.CouchPotato.Models; using Ombi.Api.Lidarr; using Ombi.Api.Lidarr.Models; using Ombi.Api.TheMovieDb; @@ -30,7 +25,6 @@ using Ombi.Settings.Settings.Models.Notifications; using Ombi.Store.Entities; using Ombi.Store.Repository; -using Org.BouncyCastle.Utilities.Collections; using Quartz; using ContentType = Ombi.Store.Entities.ContentType; @@ -122,86 +116,37 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) try { - - var customization = await _customizationSettings.GetSettingsAsync(); - var plexContent = (IQueryable)_plex.GetAll().Include(x => x.Episodes).AsNoTracking(); - var embyContent = (IQueryable)_emby.GetAll().Include(x => x.Episodes).AsNoTracking(); - var jellyfinContent = (IQueryable)_jellyfin.GetAll().Include(x => x.Episodes).AsNoTracking(); - - // MOVIES - var moviesContents = new List>(); - moviesContents.Add((await GetMoviesContent(_plex)).AsQueryable()); - moviesContents.Add((await GetMoviesContent(_emby)).AsQueryable()); - moviesContents.Add((await GetMoviesContent(_jellyfin)).AsQueryable()); - - // MUSIC - var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable); - var addedLog = _recentlyAddedLog.GetAll().ToList(); - HashSet addedAlbumLogIds; - GetRecentlyAddedMoviesData(addedLog, out addedAlbumLogIds); - - // EPISODES - 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); - var addedJellyfinEpisodesLogIds = - addedLog.Where(x => x.Type == RecentlyAddedType.Jellyfin && x.ContentType == ContentType.Episode); - - - // Filter out the ones that we haven't sent yet - var lidarrContentAlbumsToSend = lidarrContent.Where(x => !addedAlbumLogIds.Contains(x.ForeignAlbumId)).ToHashSet(); - _log.LogInformation("Albums to send: {0}", lidarrContentAlbumsToSend.Count()); - - var plexEpisodesToSend = - FilterEpisodes(_plex.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), addedPlexEpisodesLogIds); - var embyEpisodesToSend = FilterEpisodes(_emby.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), - addedEmbyEpisodesLogIds); - var jellyfinEpisodesToSend = FilterEpisodes(_jellyfin.GetAllEpisodes().Include(x => x.Series).AsNoTracking(), - addedJellyfinEpisodesLogIds); - - _log.LogInformation("Plex Episodes to send: {0}", plexEpisodesToSend.Count()); - _log.LogInformation("Emby Episodes to send: {0}", embyEpisodesToSend.Count()); - _log.LogInformation("Jellyfin Episodes to send: {0}", jellyfinEpisodesToSend.Count()); var plexSettings = await _plexSettings.GetSettingsAsync(); var embySettings = await _embySettings.GetSettingsAsync(); var jellyfinSettings = await _jellyfinSettings.GetSettingsAsync(); - var body = string.Empty; - if (test) + + var customization = await _customizationSettings.GetSettingsAsync(); + + var moviesContents = new List(); + var seriesContents = new List(); + if (plexSettings.Enable) { - var plexm = plexContent.Where(x => x.Type == MediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10); - var embym = embyContent.Where(x => x.Type == MediaType.Movie).OrderByDescending(x => x.AddedAt).Take(10); - var jellyfinm = jellyfinContent.Where(x => x.Type == MediaType.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.Series.AddedAt).Take(10).ToHashSet(); - var jellyfint = _jellyfin.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet(); - var lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet(); - - var moviesProviders = new List>() { - plexm, - embym, - jellyfinm - }; - var seriesProviders = new List>() { - plext, - embyt, - jellyfint - }; - body = await BuildHtml(moviesProviders, seriesProviders, lidarr, settings, embySettings, jellyfinSettings, plexSettings); + moviesContents.AddRange(await GetMoviesContent(_plex, test)); + seriesContents.AddRange(GetSeriesContent(_plex, test)); } - else + if (embySettings.Enable) { - var seriesProviders = new List>() { - plexEpisodesToSend, - embyEpisodesToSend, - jellyfinEpisodesToSend - }; - - body = await BuildHtml(moviesContents, seriesProviders, lidarrContentAlbumsToSend, settings, embySettings, jellyfinSettings, plexSettings); - if (body.IsNullOrEmpty()) - { - return; - } + moviesContents.AddRange(await GetMoviesContent(_emby, test)); + seriesContents.AddRange(GetSeriesContent(_emby, test)); + } + if (jellyfinSettings.Enable) + { + moviesContents.AddRange(await GetMoviesContent(_jellyfin, test)); + seriesContents.AddRange(GetSeriesContent(_jellyfin, test)); + } + + var albumsContents = GetMusicContent(_lidarrAlbumRepository, test); + + var body = await BuildHtml(moviesContents, seriesContents, albumsContents, settings); + + if (body.IsNullOrEmpty()) + { + return; } if (!test) @@ -257,46 +202,7 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) // Now add all of this to the Recently Added log var recentlyAddedLog = new HashSet(); AddToRecentlyAddedLog(moviesContents, recentlyAddedLog); - - 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 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 - }); - } - - foreach (var p in jellyfinEpisodesToSend) - { - recentlyAddedLog.Add(new RecentlyAddedLog - { - AddedAt = DateTime.Now, - Type = RecentlyAddedType.Jellyfin, - ContentType = ContentType.Episode, - ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), - EpisodeNumber = p.EpisodeNumber, - SeasonNumber = p.SeasonNumber - }); - } - + AddToRecentlyAddedLog(seriesContents, recentlyAddedLog); await _recentlyAddedLog.AddRange(recentlyAddedLog); } else @@ -336,22 +242,34 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) .SendAsync(NotificationHub.NotificationEvent, "Newsletter Finished"); } - private void AddToRecentlyAddedLog(List> moviesContents, + private void AddToRecentlyAddedLog(ICollection moviesContents, HashSet recentlyAddedLog) { - foreach (var contentProvider in moviesContents) + foreach (var p in moviesContents) { - foreach (var p in contentProvider) + recentlyAddedLog.Add(new RecentlyAddedLog { - recentlyAddedLog.Add(new RecentlyAddedLog - { - AddedAt = DateTime.Now, - Type = p.Repository.RecentlyAddedType, - ContentType = ContentType.Parent, - ContentId = StringHelper.IntParseLinq(p.TheMovieDbId), - }); - - } + AddedAt = DateTime.Now, + Type = p.Repository?.RecentlyAddedType ?? RecentlyAddedType.Plex, // TODO + ContentType = ContentType.Parent, + ContentId = StringHelper.IntParseLinq(p.TheMovieDbId), + }); + } + } + private void AddToRecentlyAddedLog(ICollection episodes, + HashSet recentlyAddedLog) + { + foreach (var p in episodes) + { + recentlyAddedLog.Add(new RecentlyAddedLog + { + AddedAt = DateTime.Now, + Type = p.Series.Repository?.RecentlyAddedType ?? RecentlyAddedType.Plex, // TODO + ContentType = ContentType.Episode, + ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), + EpisodeNumber = p.EpisodeNumber, + SeasonNumber = p.SeasonNumber + }); } } @@ -361,24 +279,80 @@ private void GetRecentlyAddedMoviesData(List addedLog, out Has addedAlbumLogIds = lidarrParent != null && lidarrParent.Any() ? (lidarrParent?.Select(x => x.AlbumId)?.ToHashSet() ?? new HashSet()) : new HashSet(); } - private async Task> GetMoviesContent(IMediaServerContentRepository repository) where T : class, IMediaServerContent + private async Task> GetMoviesContent(IMediaServerContentRepository repository, bool test) where T : class, IMediaServerContent { - IQueryable content = repository.GetAll().Include(x => x.Episodes).AsNoTracking(); + IQueryable content = repository.GetAll().Include(x => x.Episodes).AsNoTracking().Where(x => x.Type == MediaType.Movie).OrderByDescending(x => x.AddedAt); var localDataset = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - // Filter out the ones that we haven't sent yet - var addedLog = _recentlyAddedLog.GetAll().ToList(); - var parent = addedLog.Where(x => x.Type == repository.RecentlyAddedType - && x.ContentType == ContentType.Parent).ToList(); - var addedMovieLogIds = parent != null && parent.Any() ? (parent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet()) : new HashSet(); - var contentMoviesToSend = localDataset.Where(x => !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); - _log.LogInformation("Movies to send: {0}", contentMoviesToSend.Count()); - // Find the movies that do not yet have MovieDbIds - var needsMovieDb = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var newMovies = await GetMoviesWithoutId(addedMovieLogIds, needsMovieDb, repository); - contentMoviesToSend = contentMoviesToSend.Union(newMovies).ToHashSet(); + HashSet moviesToSend; + if (test) + { + moviesToSend = content.Take(10).ToHashSet(); + } + else + { + // Filter out the ones that we haven't sent yet + var parent = _recentlyAddedLog.GetAll().Where(x => x.Type == repository.RecentlyAddedType + && x.ContentType == ContentType.Parent).ToList(); + var addedMovieLogIds = parent != null && parent.Any() ? (parent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet()) : new HashSet(); + moviesToSend = localDataset.Where(x => !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); + _log.LogInformation("Movies to send: {0}", moviesToSend.Count()); + + // Find the movies that do not yet have MovieDbIds + var needsMovieDb = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var newMovies = await GetMoviesWithoutId(addedMovieLogIds, needsMovieDb, repository); + moviesToSend = moviesToSend.Union(newMovies).ToHashSet(); + } + + _log.LogInformation("Movies to send: {0}", moviesToSend.Count()); + return moviesToSend.DistinctBy(x => x.Id).ToHashSet(); + } + + private HashSet GetSeriesContent(IMediaServerContentRepository repository, bool test) where T : class, IMediaServerContent + { + var content = repository.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).AsNoTracking(); + + HashSet episodesToSend; + if (test) + { + var count = repository.GetAllEpisodes().Count(); + _log.LogCritical($"Episodes test mode {count}"); + _log.LogCritical(nameof(repository)); + episodesToSend = content.Take(10).ToHashSet(); + } + else + { + // Filter out the ones that we haven't sent yet + var addedEpisodesLogIds = + _recentlyAddedLog.GetAll().Where(x => x.Type == repository.RecentlyAddedType && x.ContentType == ContentType.Episode); + episodesToSend = + FilterEpisodes(content, addedEpisodesLogIds); + } + + _log.LogInformation("Episodes to send: {0}", episodesToSend.Count()); + return episodesToSend; - return contentMoviesToSend.DistinctBy(x => x.Id).ToHashSet(); + } + private HashSet GetMusicContent(IExternalRepository repository, bool test) + { + + var lidarrContent = repository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable); + + HashSet albumsToSend; + if (test) + { + albumsToSend = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet(); + } + else + { + // Filter out the ones that we haven't sent yet + var addedLog = _recentlyAddedLog.GetAll().ToList(); + HashSet addedAlbumLogIds; + GetRecentlyAddedMoviesData(addedLog, out addedAlbumLogIds); + albumsToSend = lidarrContent.Where(x => !addedAlbumLogIds.Contains(x.ForeignAlbumId)).ToHashSet(); + } + _log.LogInformation("Albums to send: {0}", albumsToSend.Count()); + return albumsToSend; } @@ -463,9 +437,8 @@ private NotificationMessageContent ParseTemplate(NotificationTemplates template, return resolver.ParseMessage(template, curlys); } - private async Task BuildHtml(ICollection> contentToSend, - ICollection> episodes, HashSet albums, NewsletterSettings settings, EmbySettings embySettings, JellyfinSettings jellyfinSettings, - PlexSettings plexSettings) + private async Task BuildHtml(ICollection movies, + IEnumerable episodes, HashSet albums, NewsletterSettings settings) { var ombiSettings = await _ombiSettings.GetSettingsAsync(); sb = new StringBuilder(); @@ -479,10 +452,7 @@ private async Task BuildHtml(ICollection sb.Append("
"); @@ -499,10 +469,7 @@ private async Task BuildHtml(ICollection sb.Append(""); @@ -531,10 +498,10 @@ private async Task BuildHtml(ICollection return sb.ToString(); } - private async Task ProcessMovies(IQueryable plexContentToSend, string defaultLanguageCode, string mediaServerUrl) + private async Task ProcessMovies(ICollection plexContentToSend, string defaultLanguageCode) { int count = 0; - var ordered = plexContentToSend.OrderByDescending(x => x.AddedAt); + var ordered = plexContentToSend; foreach (var content in ordered) { int.TryParse(content.TheMovieDbId, out var movieDbId); @@ -543,7 +510,7 @@ private async Task ProcessMovies(IQueryable plexContentToSe continue; } var info = await _movieApi.GetMovieInformationWithExtraInfo(movieDbId, defaultLanguageCode); - var mediaurl = PlexHelper.BuildPlexMediaUrl(content.Url, mediaServerUrl); + var mediaurl = content.GetExternalUrl(); if (info == null) { continue; @@ -676,7 +643,7 @@ private void CreateAlbumHtmlContent(AlbumLookup info) AddGenres($"Type: {info.albumType}"); } - private async Task ProcessTv(IEnumerable episodes, string languageCode, string serverHostname) + private async Task ProcessTv(IEnumerable episodes, string languageCode) { var series = new List(); foreach (var episode in episodes) @@ -753,7 +720,7 @@ private async Task ProcessTv(IEnumerable episodes, string l AddBackgroundInsideTable($"https://image.tmdb.org/t/p/w1280/"); } AddPosterInsideTable(banner); - AddMediaServerUrl(PlexHelper.BuildPlexMediaUrl(t.Url, serverHostname), banner); + AddMediaServerUrl(t.GetExternalUrl(), banner); AddInfoTable(); AddTvTitle(info, tvInfo); diff --git a/src/Ombi.Store/Entities/IMediaServerContent.cs b/src/Ombi.Store/Entities/IMediaServerContent.cs index 806602ee9..889f66c1c 100644 --- a/src/Ombi.Store/Entities/IMediaServerContent.cs +++ b/src/Ombi.Store/Entities/IMediaServerContent.cs @@ -15,6 +15,7 @@ public interface IMediaServerContent: IEntity public IMediaServerContentRepositoryLight Repository { get; } public string Url { get; set; } + public string GetExternalUrl(); public ICollection Episodes { get; set; } diff --git a/src/Ombi.Store/Entities/MediaServerContent.cs b/src/Ombi.Store/Entities/MediaServerContent.cs index 8055d0d95..83cc3059b 100644 --- a/src/Ombi.Store/Entities/MediaServerContent.cs +++ b/src/Ombi.Store/Entities/MediaServerContent.cs @@ -30,6 +30,10 @@ public abstract class MediaServerContent: Entity, IMediaServerContent [NotMapped] //TODO: instantiate this variable upon read // something in ExternalContext.cs? public IMediaServerContentRepositoryLight Repository { get; set; } + + public string GetExternalUrl() { + return string.Empty; // TODO + } } public abstract class MediaServerEpisode: Entity, IMediaServerEpisode From 468847b103f7ae28ffc373bbf227a760fe5a5e58 Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Sun, 16 Jan 2022 19:32:26 +0100 Subject: [PATCH 10/21] Clean up leftovers --- .../Jobs/Emby/EmbyContentSync.cs | 4 +-- .../Jobs/Jellyfin/JellyfinContentSync.cs | 6 ++-- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 8 ++--- .../Jobs/Plex/PlexContentSync.cs | 6 ++-- src/Ombi.Store/Entities/EmbyContent.cs | 1 + .../Entities/IMediaServerContent.cs | 4 +-- src/Ombi.Store/Entities/JellyfinContent.cs | 1 + src/Ombi.Store/Entities/MediaServerContent.cs | 8 ++--- src/Ombi.Store/Entities/PlexServerContent.cs | 2 ++ .../IMediaServerContentRepository.cs | 8 ++++- .../IMediaServerContentRepositoryLight.cs | 30 ------------------- .../Repository/IPlexContentRepository.cs | 2 +- .../Repository/MediaServerRepository.cs | 5 ---- .../Repository/PlexContentRepository.cs | 8 ++--- 14 files changed, 28 insertions(+), 65 deletions(-) delete mode 100644 src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs diff --git a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs index 8cf58391d..cb7eaefd3 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs @@ -169,7 +169,6 @@ private async Task ProcessTv(EmbyServers server, bool recentlyAdded, string pare EmbyId = tvShow.Id, Url = EmbyHelper.GetEmbyMediaUrl(tvShow.Id, server?.ServerId, server.ServerHostname), AddedAt = DateTime.UtcNow, - Repository = _repo }); } else @@ -259,8 +258,7 @@ private async Task ProcessMovies(EmbyMovie movieInfo, ICollection c Type = MediaType.Movie, EmbyId = movieInfo.Id, Url = EmbyHelper.GetEmbyMediaUrl(movieInfo.Id, server?.ServerId, server.ServerHostname), - AddedAt = DateTime.UtcNow, - Repository = _repo + AddedAt = DateTime.UtcNow }); } else diff --git a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs index 1789498e3..60ee42210 100644 --- a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs @@ -146,8 +146,7 @@ private async Task ProcessTv(JellyfinServers server, string parentId = default) Type = MediaType.Series, JellyfinId = tvShow.Id, Url = JellyfinHelper.GetJellyfinMediaUrl(tvShow.Id, server?.ServerId, server.ServerHostname), - AddedAt = DateTime.UtcNow, - Repository = _repo + AddedAt = DateTime.UtcNow }); } else @@ -227,8 +226,7 @@ private async Task ProcessMovies(JellyfinMovie movieInfo, ICollection moviesConten recentlyAddedLog.Add(new RecentlyAddedLog { AddedAt = DateTime.Now, - Type = p.Repository?.RecentlyAddedType ?? RecentlyAddedType.Plex, // TODO + Type = p.RecentlyAddedType, ContentType = ContentType.Parent, ContentId = StringHelper.IntParseLinq(p.TheMovieDbId), }); @@ -264,7 +264,7 @@ private void AddToRecentlyAddedLog(ICollection episodes, recentlyAddedLog.Add(new RecentlyAddedLog { AddedAt = DateTime.Now, - Type = p.Series.Repository?.RecentlyAddedType ?? RecentlyAddedType.Plex, // TODO + Type = p.Series.RecentlyAddedType, ContentType = ContentType.Episode, ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), EpisodeNumber = p.EpisodeNumber, @@ -510,7 +510,7 @@ private async Task ProcessMovies(ICollection plexContentToS continue; } var info = await _movieApi.GetMovieInformationWithExtraInfo(movieDbId, defaultLanguageCode); - var mediaurl = content.GetExternalUrl(); + var mediaurl = content.Url; if (info == null) { continue; @@ -720,7 +720,7 @@ private async Task ProcessTv(IEnumerable episodes, string l AddBackgroundInsideTable($"https://image.tmdb.org/t/p/w1280/"); } AddPosterInsideTable(banner); - AddMediaServerUrl(t.GetExternalUrl(), banner); + AddMediaServerUrl(t.Url, banner); AddInfoTable(); AddTvTitle(info, tvInfo); diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index c2a9d20bf..637d7591d 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -353,8 +353,7 @@ public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet Title = movie.title, Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey), Seasons = new List(), - Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty, - Repository = Repo + Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty }; if (providerIds.ImdbId.HasValue()) { @@ -557,8 +556,7 @@ private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet(), - Repository = Repo + Seasons = new List() }; await GetProviderIds(showMetadata, item); diff --git a/src/Ombi.Store/Entities/EmbyContent.cs b/src/Ombi.Store/Entities/EmbyContent.cs index 07fb1110e..4005e7a48 100644 --- a/src/Ombi.Store/Entities/EmbyContent.cs +++ b/src/Ombi.Store/Entities/EmbyContent.cs @@ -40,6 +40,7 @@ public class EmbyContent : MediaServerContent /// public string ProviderId { get; set; } public string EmbyId { get; set; } + public override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Emby; } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/IMediaServerContent.cs b/src/Ombi.Store/Entities/IMediaServerContent.cs index 889f66c1c..3e78dffcc 100644 --- a/src/Ombi.Store/Entities/IMediaServerContent.cs +++ b/src/Ombi.Store/Entities/IMediaServerContent.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; -using Ombi.Store.Repository; namespace Ombi.Store.Entities { @@ -12,10 +11,9 @@ public interface IMediaServerContent: IEntity public string TvDbId { get; set; } public string TheMovieDbId { get; set; } public MediaType Type { get; set; } - public IMediaServerContentRepositoryLight Repository { get; } + public RecentlyAddedType RecentlyAddedType{ get; } public string Url { get; set; } - public string GetExternalUrl(); public ICollection Episodes { get; set; } diff --git a/src/Ombi.Store/Entities/JellyfinContent.cs b/src/Ombi.Store/Entities/JellyfinContent.cs index a3744adeb..da77c910c 100644 --- a/src/Ombi.Store/Entities/JellyfinContent.cs +++ b/src/Ombi.Store/Entities/JellyfinContent.cs @@ -40,6 +40,7 @@ public class JellyfinContent : MediaServerContent /// public string ProviderId { get; set; } public string JellyfinId { get; set; } + public override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Jellyfin; } } diff --git a/src/Ombi.Store/Entities/MediaServerContent.cs b/src/Ombi.Store/Entities/MediaServerContent.cs index 83cc3059b..ab99090f4 100644 --- a/src/Ombi.Store/Entities/MediaServerContent.cs +++ b/src/Ombi.Store/Entities/MediaServerContent.cs @@ -27,13 +27,9 @@ public abstract class MediaServerContent: Entity, IMediaServerContent [NotMapped] public bool HasTheMovieDb => !string.IsNullOrEmpty(TheMovieDbId); - - [NotMapped] //TODO: instantiate this variable upon read // something in ExternalContext.cs? - public IMediaServerContentRepositoryLight Repository { get; set; } - public string GetExternalUrl() { - return string.Empty; // TODO - } + [NotMapped] + public abstract RecentlyAddedType RecentlyAddedType { get; } } public abstract class MediaServerEpisode: Entity, IMediaServerEpisode diff --git a/src/Ombi.Store/Entities/PlexServerContent.cs b/src/Ombi.Store/Entities/PlexServerContent.cs index c2e6b8de0..a9116ad16 100644 --- a/src/Ombi.Store/Entities/PlexServerContent.cs +++ b/src/Ombi.Store/Entities/PlexServerContent.cs @@ -51,6 +51,8 @@ public ICollection PlexEpisodes get => (ICollection)Episodes; set => Episodes = (ICollection)value; } + + public override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Plex; } [Table("PlexSeasonsContent")] diff --git a/src/Ombi.Store/Repository/IMediaServerContentRepository.cs b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs index 1f81a40ba..73cc00fde 100644 --- a/src/Ombi.Store/Repository/IMediaServerContentRepository.cs +++ b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs @@ -5,8 +5,14 @@ namespace Ombi.Store.Repository { - public interface IMediaServerContentRepository : IExternalRepository, IMediaServerContentRepositoryLight + public interface IMediaServerContentRepository : IExternalRepository where Content : IMediaServerContent { + RecentlyAddedType RecentlyAddedType{ get; } + Task Update(IMediaServerContent existingContent); + IQueryable GetAllEpisodes(); + Task Add(IMediaServerEpisode content); + Task AddRange(IEnumerable content); + void UpdateWithoutSave(IMediaServerContent existingContent); } } \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs b/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs deleted file mode 100644 index 1f1749ae8..000000000 --- a/src/Ombi.Store/Repository/IMediaServerContentRepositoryLight.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Ombi.Store.Entities; - -namespace Ombi.Store.Repository -{ - // TOOD: this is a mess done to bypass the fact that - // I can't pass around IMediaServerContentRepository as a parameter - // because I want to pass it a generic IMediaServerContent as a 'type' - // and casting from concrete classes doesn't work due to my poor C# knowledge - - // My workaround so far has been to use this lightened interface, - // but the ever-growing number of wrapper methods for methods coming from IRepository - // is starting to smell (see implementing class MediaServerContentRepository). - public interface IMediaServerContentRepositoryLight - { - RecentlyAddedType RecentlyAddedType{ get; } - Task Update(IMediaServerContent existingContent); - - // IQueryable GetAllContent(); - // Task FindContent(object key); - // Task SaveChangesAsync(); - - IQueryable GetAllEpisodes(); - Task Add(IMediaServerEpisode content); - Task AddRange(IEnumerable content); - void UpdateWithoutSave(IMediaServerContent existingContent); - } -} \ No newline at end of file diff --git a/src/Ombi.Store/Repository/IPlexContentRepository.cs b/src/Ombi.Store/Repository/IPlexContentRepository.cs index 8203959bc..f3c6d0ae2 100644 --- a/src/Ombi.Store/Repository/IPlexContentRepository.cs +++ b/src/Ombi.Store/Repository/IPlexContentRepository.cs @@ -12,7 +12,7 @@ public interface IPlexContentRepository : IMediaServerContentRepository ContentExists(string providerId); Task Get(string providerId, ProviderType type); - Task GetByType(string providerId, ProviderType type, MediaType MediaServerType); + Task GetByType(string providerId, ProviderType type, MediaType mediaType); Task GetByKey(int key); Task GetEpisodeByKey(int key); IEnumerable GetWhereContentByCustom(Expression> predicate); diff --git a/src/Ombi.Store/Repository/MediaServerRepository.cs b/src/Ombi.Store/Repository/MediaServerRepository.cs index 3fdc35ea8..0f458ee2b 100644 --- a/src/Ombi.Store/Repository/MediaServerRepository.cs +++ b/src/Ombi.Store/Repository/MediaServerRepository.cs @@ -17,11 +17,6 @@ public MediaServerContentRepository(ExternalContext db) : base(db) } public abstract Task Update(IMediaServerContent existingContent); - - // TOOD: this smells: trying to wrap ExternalRepository methods in IMediaServerContentRepositoryLight for generic consumption - public IQueryable GetAllContent() => (IQueryable)GetAll(); - public async Task FindContent(object key) => (IMediaServerContent)await Find(key); - public abstract IQueryable GetAllEpisodes(); public abstract Task Add(IMediaServerEpisode content); public abstract Task AddRange(IEnumerable content); diff --git a/src/Ombi.Store/Repository/PlexContentRepository.cs b/src/Ombi.Store/Repository/PlexContentRepository.cs index 6429e679f..db7251987 100644 --- a/src/Ombi.Store/Repository/PlexContentRepository.cs +++ b/src/Ombi.Store/Repository/PlexContentRepository.cs @@ -75,16 +75,16 @@ public async Task Get(string providerId, ProviderType type) return null; } - public async Task GetByType(string providerId, ProviderType type, MediaType plexType) + public async Task GetByType(string providerId, ProviderType type, MediaType mediaType) { switch (type) { case ProviderType.ImdbId: - return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.ImdbId == providerId && x.Type == plexType); + return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.ImdbId == providerId && x.Type == mediaType); case ProviderType.TheMovieDbId: - return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.TheMovieDbId == providerId && x.Type == plexType); + return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.TheMovieDbId == providerId && x.Type == mediaType); case ProviderType.TvDbId: - return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.TvDbId == providerId && x.Type == plexType); + return await Db.PlexServerContent.FirstOrDefaultAsync(x => x.TvDbId == providerId && x.Type == mediaType); default: break; } From 71a50ca6f1513964e09f73402f9160e97ea0ac2d Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Sun, 16 Jan 2022 19:50:15 +0100 Subject: [PATCH 11/21] Fix broken episodes db interaction --- src/Ombi.Store/Repository/EmbyContentRepository.cs | 2 +- src/Ombi.Store/Repository/JellyfinContentRepository.cs | 2 +- src/Ombi.Store/Repository/PlexContentRepository.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Ombi.Store/Repository/EmbyContentRepository.cs b/src/Ombi.Store/Repository/EmbyContentRepository.cs index adc260946..19bab7f76 100644 --- a/src/Ombi.Store/Repository/EmbyContentRepository.cs +++ b/src/Ombi.Store/Repository/EmbyContentRepository.cs @@ -89,7 +89,7 @@ public async Task GetEpisodeByEmbyId(string key) public override async Task AddRange(IEnumerable content) { - Db.EmbyEpisode.AddRange((EmbyEpisode)content); + Db.EmbyEpisode.AddRange((IEnumerable)content); await InternalSaveChanges(); } diff --git a/src/Ombi.Store/Repository/JellyfinContentRepository.cs b/src/Ombi.Store/Repository/JellyfinContentRepository.cs index 800473248..28cdcfae8 100644 --- a/src/Ombi.Store/Repository/JellyfinContentRepository.cs +++ b/src/Ombi.Store/Repository/JellyfinContentRepository.cs @@ -89,7 +89,7 @@ public async Task GetEpisodeByJellyfinId(string key) public override async Task AddRange(IEnumerable content) { - Db.JellyfinEpisode.AddRange((JellyfinEpisode)content); + Db.JellyfinEpisode.AddRange((IEnumerable)content); await InternalSaveChanges(); } diff --git a/src/Ombi.Store/Repository/PlexContentRepository.cs b/src/Ombi.Store/Repository/PlexContentRepository.cs index db7251987..b99ba157f 100644 --- a/src/Ombi.Store/Repository/PlexContentRepository.cs +++ b/src/Ombi.Store/Repository/PlexContentRepository.cs @@ -160,7 +160,7 @@ public async Task GetEpisodeByKey(int key) } public override async Task AddRange(IEnumerable content) { - Db.PlexEpisode.AddRange((PlexEpisode)content); + Db.PlexEpisode.AddRange((IEnumerable)content); await InternalSaveChanges(); } From 3fd43a9845d5a1a153ae1d7e8340b6628bb347dc Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Mon, 17 Jan 2022 10:26:24 +0100 Subject: [PATCH 12/21] Save absolute URL for Plex content Let's be consistent with Emby and Jellyfin --- src/Ombi.Helpers/PlexHelper.cs | 4 ++-- src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Ombi.Helpers/PlexHelper.cs b/src/Ombi.Helpers/PlexHelper.cs index 3e5aeff70..6827d0f74 100644 --- a/src/Ombi.Helpers/PlexHelper.cs +++ b/src/Ombi.Helpers/PlexHelper.cs @@ -104,11 +104,11 @@ public static ProviderId GetProviderIdFromPlexGuid(string guid) return new ProviderId(); } - public static string GetPlexMediaUrl(string machineId, int mediaId) + public static string GetPlexMediaUrl(string machineId, int mediaId, string plexHost) { var url = $"web/#!/server/{machineId}/details?key=%2flibrary%2Fmetadata%2F{mediaId}"; - return url; + return BuildPlexMediaUrl(url, plexHost); } public static string BuildPlexMediaUrl(string savedUrl, string plexHost) diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index 637d7591d..f24f7a6c3 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -351,7 +351,7 @@ public async Task MovieLoop(PlexServers servers, Mediacontainer content, HashSet ReleaseYear = movie.year.ToString(), Type = MediaType.Movie, Title = movie.title, - Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey), + Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey, servers.ServerHostname), Seasons = new List(), Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty }; @@ -555,7 +555,7 @@ private async Task ProcessTvShow(PlexServers servers, Metadata show, HashSet() }; await GetProviderIds(showMetadata, item); From 26177e523672770ba3ec365c3de43a22aa4f7fcf Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Mon, 17 Jan 2022 10:32:22 +0100 Subject: [PATCH 13/21] Fix broken integration with Plex libraries --- .../Jobs/Plex/PlexContentSync.cs | 6 +-- .../Jobs/Plex/PlexEpisodeSync.cs | 2 +- src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs | 37 +++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index f24f7a6c3..df96457d0 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -182,7 +182,7 @@ private async Task ProcessServer(PlexServers servers, bool rec foreach (var content in allContent.OrderByDescending(x => x.viewGroup)) { Logger.LogDebug($"Got type '{content.viewGroup}' to process"); - if (content.viewGroup.Equals(MediaType.Episode.ToString(), StringComparison.InvariantCultureIgnoreCase)) + if (content.viewGroup.Equals(PlexMediaType.Episode.ToString(), StringComparison.InvariantCultureIgnoreCase)) { Logger.LogDebug("Found some episodes, this must be a recently added sync"); var count = 0; @@ -230,7 +230,7 @@ private async Task ProcessServer(PlexServers servers, bool rec episodesProcessed.AddRange(episodesAdded.Select(x => x.Id)); } } - if (content.viewGroup.Equals(MediaType.Series.ToString(), StringComparison.InvariantCultureIgnoreCase)) + if (content.viewGroup.Equals(PlexMediaType.Show.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // Process Shows Logger.LogDebug("Processing TV Shows"); @@ -260,7 +260,7 @@ private async Task ProcessServer(PlexServers servers, bool rec await Repo.SaveChangesAsync(); } - if (content.viewGroup.Equals(MediaType.Movie.ToString(), StringComparison.InvariantCultureIgnoreCase)) + if (content.viewGroup.Equals(PlexMediaType.Movie.ToString(), StringComparison.InvariantCultureIgnoreCase)) { await MovieLoop(servers, content, contentToAdd, contentProcessed); } diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs index ad36cb6ea..4a088ca7b 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs @@ -83,7 +83,7 @@ private async Task Cache(PlexServers settings) var sections = await _api.GetLibrarySections(settings.PlexAuthToken, settings.FullUri); // Filter the libSections - var tvSections = sections.MediaContainer.Directory.Where(x => x.type.Equals(MediaType.Series.ToString(), StringComparison.CurrentCultureIgnoreCase)); + var tvSections = sections.MediaContainer.Directory.Where(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)); foreach (var section in tvSections) { diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs b/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs new file mode 100644 index 000000000..2e2e9229e --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Plex/PlexMediaType.cs @@ -0,0 +1,37 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: PlexContentCacher.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + + +namespace Ombi.Schedule.Jobs +{ + public enum PlexMediaType + { + Movie = 0, + Show = 1, + Episode = 2, + } +} \ No newline at end of file From 34bc1f48cb11527476eefcb4b7462f4063613c30 Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Mon, 17 Jan 2022 11:11:11 +0100 Subject: [PATCH 14/21] Fix error when multiple media servers configured --- src/Ombi.Store/Entities/EmbyEpisode.cs | 7 ++++--- src/Ombi.Store/Entities/IMediaServerContent.cs | 2 +- src/Ombi.Store/Entities/JellyfinEpisode.cs | 5 +++-- src/Ombi.Store/Entities/MediaServerContent.cs | 3 ++- src/Ombi.Store/Entities/PlexEpisode.cs | 4 ++-- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Ombi.Store/Entities/EmbyEpisode.cs b/src/Ombi.Store/Entities/EmbyEpisode.cs index 1d2a03b46..97fdb09b1 100644 --- a/src/Ombi.Store/Entities/EmbyEpisode.cs +++ b/src/Ombi.Store/Entities/EmbyEpisode.cs @@ -51,12 +51,13 @@ public EmbyContent EmbySeries get => (EmbyContent)Series; set => Series = value; } - - public override IMediaServerContent SeriesIsIn(List content) + + public override IMediaServerContent SeriesIsIn(ICollection content) { - return content.Cast().FirstOrDefault( + return content.OfType().FirstOrDefault( x => x.EmbyId == this.EmbySeries.EmbyId); } + public override bool IsIn(IMediaServerContent content) { return content.Episodes.Cast().Any(x => x.EmbyId == this.EmbyId); diff --git a/src/Ombi.Store/Entities/IMediaServerContent.cs b/src/Ombi.Store/Entities/IMediaServerContent.cs index 3e78dffcc..25e4d5f50 100644 --- a/src/Ombi.Store/Entities/IMediaServerContent.cs +++ b/src/Ombi.Store/Entities/IMediaServerContent.cs @@ -43,7 +43,7 @@ public interface IMediaServerEpisode public IMediaServerContent Series { get; set; } - public IMediaServerContent SeriesIsIn(List content); + public IMediaServerContent SeriesIsIn(ICollection content); public bool IsIn(IMediaServerContent content); } diff --git a/src/Ombi.Store/Entities/JellyfinEpisode.cs b/src/Ombi.Store/Entities/JellyfinEpisode.cs index 890cf3c2a..1c0ac423e 100644 --- a/src/Ombi.Store/Entities/JellyfinEpisode.cs +++ b/src/Ombi.Store/Entities/JellyfinEpisode.cs @@ -53,11 +53,12 @@ public JellyfinContent JellyfinSeries set => Series = value; } - public override IMediaServerContent SeriesIsIn(List content) + public override IMediaServerContent SeriesIsIn(ICollection content) { - return content.Cast().FirstOrDefault( + return content.OfType().FirstOrDefault( x => x.JellyfinId == this.JellyfinSeries.JellyfinId); } + public override bool IsIn(IMediaServerContent content) { return content.Episodes.Cast().Any(x => x.JellyfinId == this.JellyfinId); diff --git a/src/Ombi.Store/Entities/MediaServerContent.cs b/src/Ombi.Store/Entities/MediaServerContent.cs index ab99090f4..3bccfea06 100644 --- a/src/Ombi.Store/Entities/MediaServerContent.cs +++ b/src/Ombi.Store/Entities/MediaServerContent.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel.DataAnnotations.Schema; using Ombi.Store.Repository; @@ -40,7 +41,7 @@ public abstract class MediaServerEpisode: Entity, IMediaServerEpisode public IMediaServerContent Series { get; set; } - public abstract IMediaServerContent SeriesIsIn(List content); + public abstract IMediaServerContent SeriesIsIn(ICollection content); public abstract bool IsIn(IMediaServerContent content); } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/PlexEpisode.cs b/src/Ombi.Store/Entities/PlexEpisode.cs index 9d7ca87c8..ac482d7ac 100644 --- a/src/Ombi.Store/Entities/PlexEpisode.cs +++ b/src/Ombi.Store/Entities/PlexEpisode.cs @@ -23,9 +23,9 @@ public PlexServerContent PlexSeries set => Series = value; } - public override IMediaServerContent SeriesIsIn(List content) + public override IMediaServerContent SeriesIsIn(ICollection content) { - return content.Cast().FirstOrDefault( + return content.OfType().FirstOrDefault( x => x.Key == this.PlexSeries.Key); } From 1b6e97a0ae466b22501427b8b29e79dea1489f8d Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Mon, 17 Jan 2022 11:19:21 +0100 Subject: [PATCH 15/21] Fix newsletter being sent if no movies or episodes --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 4659e95cd..68a2a7faf 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -443,7 +443,7 @@ private async Task BuildHtml(ICollection movies, var ombiSettings = await _ombiSettings.GetSettingsAsync(); sb = new StringBuilder(); - if (!settings.DisableMovies) + if (movies.Any() && !settings.DisableMovies) { sb.Append("

New Movies



"); sb.Append( @@ -460,7 +460,7 @@ private async Task BuildHtml(ICollection movies, sb.Append("
"); sb.AppendFormat("", url); } - protected virtual void AddMediaServerUrl(StringBuilder sb, string mediaurl, string url) + protected virtual void AddMediaServerUrl(string mediaurl, string url) { if (url.HasValue()) { @@ -41,14 +42,14 @@ protected virtual void AddMediaServerUrl(StringBuilder sb, string mediaurl, stri sb.Append(""); } - protected virtual void AddInfoTable(StringBuilder sb) + protected virtual void AddInfoTable() { sb.Append( ""); foreach (var mediaServerContent in episodes) { - await ProcessTv(mediaServerContent, sb, ombiSettings.DefaultLanguageCode, /* plexSettings.Servers.FirstOrDefault()?.ServerHostname ?? */ string.Empty); + await ProcessTv(mediaServerContent, ombiSettings.DefaultLanguageCode, /* plexSettings.Servers.FirstOrDefault()?.ServerHostname ?? */ string.Empty); } sb.Append(""); sb.Append("
"); sb.Append(""); } - protected virtual void AddTitle(StringBuilder sb, string url, string title) + protected virtual void AddTitle( string url, string title) { sb.Append(""); sb.Append(""); } - protected virtual void AddParagraph(StringBuilder sb, string text) + protected virtual void AddParagraph(string text) { sb.Append(""); sb.Append(""); } - protected virtual void AddTvParagraph(StringBuilder sb, string episodes, string summary) + protected virtual void AddTvParagraph(string episodes, string summary) { sb.Append(""); sb.Append(""); } - protected virtual void AddGenres(StringBuilder sb, string text) + protected virtual void AddGenres(string text) { sb.Append(""); sb.Append(""); foreach (var mediaServerContent in contentToSend) { - await ProcessMovies(mediaServerContent, sb, ombiSettings.DefaultLanguageCode, /*plexSettings.Servers?.FirstOrDefault()?.ServerHostname ?? */ string.Empty); + await ProcessMovies(mediaServerContent, ombiSettings.DefaultLanguageCode, /*plexSettings.Servers?.FirstOrDefault()?.ServerHostname ?? */ string.Empty); } sb.Append(""); sb.Append("
"); @@ -59,7 +60,7 @@ protected virtual void AddTitle(StringBuilder sb, string url, string title) sb.Append("
"); @@ -68,7 +69,7 @@ protected virtual void AddParagraph(StringBuilder sb, string text) sb.Append("
"); @@ -78,7 +79,7 @@ protected virtual void AddTvParagraph(StringBuilder sb, string episodes, string sb.Append("
"); diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 249dbb693..f4bcc1a33 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -129,9 +129,12 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) var jellyfinContent = (IQueryable)_jellyfin.GetAll().Include(x => x.Episodes).AsNoTracking(); // MOVIES - var plexContentMoviesToSend = await GetMoviesContent(plexContent, RecentlyAddedType.Plex); - var embyContentMoviesToSend = await GetMoviesContent(embyContent, RecentlyAddedType.Emby); - var jellyfinContentMoviesToSend = await GetMoviesContent(jellyfinContent, RecentlyAddedType.Jellyfin); + var moviesContents = new List>(); + // these explicit casts won't work because: + // Unable to cast object of type 'PlexServerContentRepository' to type 'IMediaServerContentRepository`1[IMediaServerContent] + moviesContents.Add((await GetMoviesContent((IMediaServerContentRepository)_plex)).AsQueryable()); + moviesContents.Add((await GetMoviesContent((IMediaServerContentRepository)_emby)).AsQueryable()); + moviesContents.Add((await GetMoviesContent((IMediaServerContentRepository)_jellyfin)).AsQueryable()); // MUSIC var lidarrContent = _lidarrAlbumRepository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable); @@ -176,12 +179,12 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) var jellyfint = _jellyfin.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).Take(10).ToHashSet(); var lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet(); - var moviesProviders = new List>() { + var moviesProviders = new List>() { plexm, embym, jellyfinm }; - var seriesProviders = new List>() { + var seriesProviders = new List>() { plext, embyt, jellyfint @@ -190,18 +193,13 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) } else { - var moviesProviders = new List>() { - plexContentMoviesToSend.AsQueryable(), - embyContentMoviesToSend.AsQueryable(), - jellyfinContentMoviesToSend.AsQueryable() - }; - var seriesProviders = new List>() { + var seriesProviders = new List>() { plexEpisodesToSend, embyEpisodesToSend, jellyfinEpisodesToSend }; - body = await BuildHtml(moviesProviders, seriesProviders, lidarrContentAlbumsToSend, settings, embySettings, jellyfinSettings, plexSettings); + body = await BuildHtml(moviesContents, seriesProviders, lidarrContentAlbumsToSend, settings, embySettings, jellyfinSettings, plexSettings); if (body.IsNullOrEmpty()) { return; @@ -260,17 +258,7 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) // Now add all of this to the Recently Added log var recentlyAddedLog = new HashSet(); - foreach (var p in plexContentMoviesToSend) - { - recentlyAddedLog.Add(new RecentlyAddedLog - { - AddedAt = DateTime.Now, - Type = RecentlyAddedType.Plex, - ContentType = ContentType.Parent, - ContentId = StringHelper.IntParseLinq(p.TheMovieDbId), - }); - - } + AddToRecentlyAddedLog(moviesContents, recentlyAddedLog); foreach (var p in plexEpisodesToSend) { @@ -284,19 +272,6 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) SeasonNumber = p.SeasonNumber }); } - foreach (var e in embyContentMoviesToSend) - { - if (e.Type == MediaType.Movie) - { - recentlyAddedLog.Add(new RecentlyAddedLog - { - AddedAt = DateTime.Now, - Type = RecentlyAddedType.Emby, - ContentType = ContentType.Parent, - ContentId = StringHelper.IntParseLinq(e.TheMovieDbId), - }); - } - } foreach (var p in embyEpisodesToSend) { @@ -311,20 +286,6 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) }); } - foreach (var e in jellyfinContentMoviesToSend) - { - if (e.Type == MediaType.Movie) - { - recentlyAddedLog.Add(new RecentlyAddedLog - { - AddedAt = DateTime.Now, - Type = RecentlyAddedType.Jellyfin, - ContentType = ContentType.Parent, - ContentId = StringHelper.IntParseLinq(e.TheMovieDbId), - }); - } - } - foreach (var p in jellyfinEpisodesToSend) { recentlyAddedLog.Add(new RecentlyAddedLog @@ -377,29 +338,49 @@ await _notification.Clients.Clients(NotificationHub.AdminConnectionIds) .SendAsync(NotificationHub.NotificationEvent, "Newsletter Finished"); } + private void AddToRecentlyAddedLog(List> moviesContents, + HashSet recentlyAddedLog) + { + foreach (var contentProvider in moviesContents) + { + foreach (var p in contentProvider) + { + recentlyAddedLog.Add(new RecentlyAddedLog + { + AddedAt = DateTime.Now, + Type = p.Repository.RecentlyAddedType, + ContentType = ContentType.Parent, + ContentId = StringHelper.IntParseLinq(p.TheMovieDbId), + }); + + } + } + } + private void GetRecentlyAddedMoviesData(List addedLog, out HashSet addedAlbumLogIds) { var lidarrParent = addedLog.Where(x => x.Type == RecentlyAddedType.Lidarr && x.ContentType == ContentType.Album); addedAlbumLogIds = lidarrParent != null && lidarrParent.Any() ? (lidarrParent?.Select(x => x.AlbumId)?.ToHashSet() ?? new HashSet()) : new HashSet(); } - private async Task> GetMoviesContent(IQueryable content, RecentlyAddedType recentlyAddedType) + private async Task> GetMoviesContent(IMediaServerContentRepository repository) { + var content = repository.GetAll().Include(x => x.Episodes).AsNoTracking(); var localDataset = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); // Filter out the ones that we haven't sent yet var addedLog = _recentlyAddedLog.GetAll().ToList(); - var plexParent = addedLog.Where(x => x.Type == recentlyAddedType + var parent = addedLog.Where(x => x.Type == repository.RecentlyAddedType && x.ContentType == ContentType.Parent).ToList(); - var addedPlexMovieLogIds = plexParent != null && plexParent.Any() ? (plexParent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet()) : new HashSet(); - var plexContentMoviesToSend = localDataset.Where(x => !addedPlexMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); - _log.LogInformation("Movies to send: {0}", plexContentMoviesToSend.Count()); + var addedMovieLogIds = parent != null && parent.Any() ? (parent?.Select(x => x.ContentId)?.ToHashSet() ?? new HashSet()) : new HashSet(); + var contentMoviesToSend = localDataset.Where(x => !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))).ToHashSet(); + _log.LogInformation("Movies to send: {0}", contentMoviesToSend.Count()); // Find the movies that do not yet have MovieDbIds - var needsMovieDbPlex = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); - var newPlexMovies = await GetMoviesWithoutId(addedPlexMovieLogIds, needsMovieDbPlex); - plexContentMoviesToSend = plexContentMoviesToSend.Union(newPlexMovies).ToHashSet(); + var needsMovieDb = content.Where(x => x.Type == MediaType.Movie && !string.IsNullOrEmpty(x.TheMovieDbId)).ToHashSet(); + var newMovies = await GetMoviesWithoutId(addedMovieLogIds, needsMovieDb, repository); + contentMoviesToSend = contentMoviesToSend.Union(newMovies).ToHashSet(); - return plexContentMoviesToSend.DistinctBy(x => x.Id).ToHashSet(); + return contentMoviesToSend.DistinctBy(x => x.Id).ToHashSet(); } @@ -418,21 +399,21 @@ public static string GenerateUnsubscribeLink(string applicationUrl, string id) return b.ToString(); } - private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDbPlex) + private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDb, IMediaServerContentRepository repository) { - foreach (var movie in needsMovieDbPlex) + foreach (var movie in needsMovieDb) { var id = await _refreshMetadata.GetTheMovieDbId(false, true, null, movie.ImdbId, movie.Title, true); movie.TheMovieDbId = id.ToString(); } - var result = needsMovieDbPlex.Where(x => x.HasTheMovieDb && !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); - await UpdateTheMovieDbId(result); + var result = needsMovieDb.Where(x => x.HasTheMovieDb && !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); + await UpdateTheMovieDbId(result, repository); // Filter them out now return result.ToHashSet(); } - private async Task UpdateTheMovieDbId(IEnumerable content) + private async Task UpdateTheMovieDbId(IEnumerable content, IMediaServerContentRepository repository) { foreach (var movie in content) { @@ -440,15 +421,15 @@ private async Task UpdateTheMovieDbId(IEnumerable content) { continue; } - var entity = await _plex.Find(movie.Id); + var entity = await repository.Find(movie.Id); if (entity == null) { return; } entity.TheMovieDbId = movie.TheMovieDbId; - _plex.UpdateWithoutSave(entity); + repository.UpdateWithoutSave(entity); } - await _plex.SaveChangesAsync(); + await repository.SaveChangesAsync(); } public async Task Execute(IJobExecutionContext job) @@ -489,7 +470,7 @@ private async Task BuildHtml(ICollection PlexSettings plexSettings) { var ombiSettings = await _ombiSettings.GetSettingsAsync(); - var sb = new StringBuilder(); + sb = new StringBuilder(); if (!settings.DisableMovies) { @@ -502,7 +483,7 @@ private async Task BuildHtml(ICollection sb.Append("
"); @@ -522,7 +503,7 @@ private async Task BuildHtml(ICollection sb.Append("
"); @@ -541,7 +522,7 @@ private async Task BuildHtml(ICollection sb.Append("
"); sb.Append(""); sb.Append(""); - await ProcessAlbums(albums, sb); + await ProcessAlbums(albums); sb.Append(""); sb.Append("
"); sb.Append("
"); sb.Append(""); sb.Append(""); - foreach (var mediaServerContent in contentToSend) - { - await ProcessMovies(mediaServerContent, ombiSettings.DefaultLanguageCode, /*plexSettings.Servers?.FirstOrDefault()?.ServerHostname ?? */ string.Empty); - } + await ProcessMovies(movies, ombiSettings.DefaultLanguageCode); sb.Append(""); sb.Append("
"); sb.Append("
"); sb.Append(""); sb.Append(""); - foreach (var mediaServerContent in episodes) - { - await ProcessTv(mediaServerContent, ombiSettings.DefaultLanguageCode, /* plexSettings.Servers.FirstOrDefault()?.ServerHostname ?? */ string.Empty); - } + await ProcessTv(episodes, ombiSettings.DefaultLanguageCode); sb.Append(""); sb.Append("
"); sb.Append("
"); } - if (!settings.DisableTv) + if (episodes.Any() && !settings.DisableTv) { sb.Append("

New TV



"); sb.Append( From efb62f72d8bfa7dcbe3a7e2d6fa35594e03baa9e Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Mon, 17 Jan 2022 16:29:40 +0100 Subject: [PATCH 16/21] Fix broken tests --- .../Rule/Request/ExistingPlexRequestRuleTests.cs | 2 +- src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs | 5 ++++- .../Rule/Search/JellyfinAvailabilityRuleTests.cs | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs b/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs index a4a278815..3cabfa438 100644 --- a/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs @@ -186,7 +186,7 @@ private void SetupMockData() TheMovieDbId = "1", Title = "Test", ReleaseYear = "2001", - Episodes = new List + Episodes = new List { new PlexEpisode { diff --git a/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs index 132f51e49..58db4329b 100644 --- a/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Search/EmbyAvailabilityRuleTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Ombi.Core.Models.Search; @@ -18,12 +19,14 @@ public class EmbyAvailabilityRuleTests public void Setup() { ContextMock = new Mock(); + LoggerMock = new Mock>(); SettingsMock = new Mock>(); - Rule = new EmbyAvailabilityRule(ContextMock.Object, SettingsMock.Object); + Rule = new EmbyAvailabilityRule(ContextMock.Object, LoggerMock.Object, SettingsMock.Object); } private EmbyAvailabilityRule Rule { get; set; } private Mock ContextMock { get; set; } + private Mock> LoggerMock { get; set; } private Mock> SettingsMock { get; set; } [Test] diff --git a/src/Ombi.Core.Tests/Rule/Search/JellyfinAvailabilityRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/JellyfinAvailabilityRuleTests.cs index 1b838f102..68c918457 100644 --- a/src/Ombi.Core.Tests/Rule/Search/JellyfinAvailabilityRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Search/JellyfinAvailabilityRuleTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Ombi.Core.Models.Search; @@ -18,12 +19,14 @@ public class JellyfinAvailabilityRuleTests public void Setup() { ContextMock = new Mock(); + LoggerMock = new Mock>(); SettingsMock = new Mock>(); - Rule = new JellyfinAvailabilityRule(ContextMock.Object, SettingsMock.Object); + Rule = new JellyfinAvailabilityRule(ContextMock.Object, LoggerMock.Object, SettingsMock.Object); } private JellyfinAvailabilityRule Rule { get; set; } private Mock ContextMock { get; set; } + private Mock> LoggerMock { get; set; } private Mock> SettingsMock { get; set; } [Test] From 2e7c2fc817364a8c4c8d657e3fc33d5c86bfce0b Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Tue, 18 Jan 2022 09:38:41 +0100 Subject: [PATCH 17/21] Remove unneccesary logs --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 68a2a7faf..49101c52a 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -316,8 +316,6 @@ private HashSet GetSeriesContent(IMediaServerContentRepo if (test) { var count = repository.GetAllEpisodes().Count(); - _log.LogCritical($"Episodes test mode {count}"); - _log.LogCritical(nameof(repository)); episodesToSend = content.Take(10).ToHashSet(); } else From 45c5c1e0a2483a2c0e0490a266717223d1ac192f Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Wed, 19 Jan 2022 12:14:40 +0100 Subject: [PATCH 18/21] Allow for newsletter localization --- src/Ombi.Core/Ombi.Core.csproj | 1 + src/Ombi.I18n/Ombi.I18n.csproj | 17 ++ src/Ombi.I18n/Resources/Texts.Designer.cs | 144 +++++++++++++++++ src/Ombi.I18n/Resources/Texts.fr.resx | 147 ++++++++++++++++++ src/Ombi.I18n/Resources/Texts.resx | 147 ++++++++++++++++++ .../NewsletterTemplate.cs | 5 + .../Ombi.Notifications.Templates.csproj | 1 + .../Templates/NewsletterTemplate.html | 4 +- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 19 +-- src/Ombi.Settings/Ombi.Settings.csproj | 1 + .../Settings/Models/OmbiSettings.cs | 14 +- 11 files changed, 487 insertions(+), 13 deletions(-) create mode 100644 src/Ombi.I18n/Ombi.I18n.csproj create mode 100644 src/Ombi.I18n/Resources/Texts.Designer.cs create mode 100644 src/Ombi.I18n/Resources/Texts.fr.resx create mode 100644 src/Ombi.I18n/Resources/Texts.resx diff --git a/src/Ombi.Core/Ombi.Core.csproj b/src/Ombi.Core/Ombi.Core.csproj index 359792e0d..0f7ca6845 100644 --- a/src/Ombi.Core/Ombi.Core.csproj +++ b/src/Ombi.Core/Ombi.Core.csproj @@ -36,6 +36,7 @@ + diff --git a/src/Ombi.I18n/Ombi.I18n.csproj b/src/Ombi.I18n/Ombi.I18n.csproj new file mode 100644 index 000000000..773215530 --- /dev/null +++ b/src/Ombi.I18n/Ombi.I18n.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + 3.0.0.0 + 3.0.0.0 + + + 8.0 + Debug;Release;NonUiBuild + + + + Always + + + \ No newline at end of file diff --git a/src/Ombi.I18n/Resources/Texts.Designer.cs b/src/Ombi.I18n/Resources/Texts.Designer.cs new file mode 100644 index 000000000..0f83e8de7 --- /dev/null +++ b/src/Ombi.I18n/Resources/Texts.Designer.cs @@ -0,0 +1,144 @@ +//------------------------------------------------------------------------------ +// +// Ce code a été généré par un outil. +// Version du runtime :4.0.30319.42000 +// +// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si +// le code est régénéré. +// +//------------------------------------------------------------------------------ + +namespace Ombi.I18n.Resources { + using System; + + + /// + /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. + /// + // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder + // à l'aide d'un outil, tel que ResGen ou Visual Studio. + // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen + // avec l'option /str ou régénérez votre projet VS. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Texts { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Texts() { + } + + /// + /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Ombi.I18n.Resources.Texts", typeof(Texts).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Remplace la propriété CurrentUICulture du thread actuel pour toutes + /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Recherche une chaîne localisée semblable à Type:. + /// + public static string AlbumTypeLabel { + get { + return ResourceManager.GetString("AlbumTypeLabel", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Episodes:. + /// + public static string EpisodesLabel { + get { + return ResourceManager.GetString("EpisodesLabel", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Genres:. + /// + public static string GenresLabel { + get { + return ResourceManager.GetString("GenresLabel", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à New Albums. + /// + public static string NewAlbums { + get { + return ResourceManager.GetString("NewAlbums", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à New Movies. + /// + public static string NewMovies { + get { + return ResourceManager.GetString("NewMovies", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à New TV. + /// + public static string NewTV { + get { + return ResourceManager.GetString("NewTV", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Powered by. + /// + public static string PoweredBy { + get { + return ResourceManager.GetString("PoweredBy", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Season:. + /// + public static string SeasonLabel { + get { + return ResourceManager.GetString("SeasonLabel", resourceCulture); + } + } + + /// + /// Recherche une chaîne localisée semblable à Unsubscribe. + /// + public static string Unsubscribe { + get { + return ResourceManager.GetString("Unsubscribe", resourceCulture); + } + } + } +} diff --git a/src/Ombi.I18n/Resources/Texts.fr.resx b/src/Ombi.I18n/Resources/Texts.fr.resx new file mode 100644 index 000000000..ea90dda73 --- /dev/null +++ b/src/Ombi.I18n/Resources/Texts.fr.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Nouveaux Albums + + + Nouveaux Films + + + Nouvelles séries + + + Genres : + + + Type : + + + Saison : + + + Épisodes : + + + Propulsé par + + + Se désinscrire + + \ No newline at end of file diff --git a/src/Ombi.I18n/Resources/Texts.resx b/src/Ombi.I18n/Resources/Texts.resx new file mode 100644 index 000000000..421371dcb --- /dev/null +++ b/src/Ombi.I18n/Resources/Texts.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + New Albums + + + New Movies + + + New TV + + + Genres: + + + Type: + + + Season: + + + Episodes: + + + Powered by + + + Unsubscribe + + \ No newline at end of file diff --git a/src/Ombi.Notifications.Templates/NewsletterTemplate.cs b/src/Ombi.Notifications.Templates/NewsletterTemplate.cs index ef31dfc4c..d731c50d3 100644 --- a/src/Ombi.Notifications.Templates/NewsletterTemplate.cs +++ b/src/Ombi.Notifications.Templates/NewsletterTemplate.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Text; +using Ombi.I18n.Resources; namespace Ombi.Notifications.Templates { @@ -30,6 +31,8 @@ public override string TemplateLocation private const string TableLocation = "{@RECENTLYADDED}"; private const string IntroText = "{@INTRO}"; private const string Unsubscribe = "{@UNSUBSCRIBE}"; + private const string UnsubscribeText = "{@UNSUBSCRIBETEXT}"; + private const string PoweredByText = "{@POWEREDBYTEXT}"; public string LoadTemplate(string subject, string intro, string tableHtml, string logo, string unsubscribeLink) @@ -41,6 +44,8 @@ public string LoadTemplate(string subject, string intro, string tableHtml, strin sb.Replace(DateKey, DateTime.Now.ToString("f")); sb.Replace(Logo, string.IsNullOrEmpty(logo) ? OmbiLogo : logo); sb.Replace(Unsubscribe, string.IsNullOrEmpty(unsubscribeLink) ? string.Empty : unsubscribeLink); + sb.Replace(UnsubscribeText, Texts.Unsubscribe); + sb.Replace(PoweredByText, Texts.PoweredBy); return sb.ToString(); } diff --git a/src/Ombi.Notifications.Templates/Ombi.Notifications.Templates.csproj b/src/Ombi.Notifications.Templates/Ombi.Notifications.Templates.csproj index 33088a591..87a876caa 100644 --- a/src/Ombi.Notifications.Templates/Ombi.Notifications.Templates.csproj +++ b/src/Ombi.Notifications.Templates/Ombi.Notifications.Templates.csproj @@ -17,6 +17,7 @@ Always + \ No newline at end of file diff --git a/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html b/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html index 71666ba67..fdafdb609 100644 --- a/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html +++ b/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html @@ -453,12 +453,12 @@ - Unsubscribe + {@UNSUBSCRIBETEXT} - Powered by Ombi + {@POWEREDBYTEXT} Ombi diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 49101c52a..83788f1b4 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -17,6 +17,7 @@ using Ombi.Core.Settings.Models.External; using Ombi.Helpers; using Ombi.Hubs; +using Ombi.I18n.Resources; using Ombi.Notifications; using Ombi.Notifications.Models; using Ombi.Notifications.Templates; @@ -264,7 +265,7 @@ private void AddToRecentlyAddedLog(ICollection episodes, recentlyAddedLog.Add(new RecentlyAddedLog { AddedAt = DateTime.Now, - Type = p.Series.RecentlyAddedType, + Type = p.Series.RecentlyAddedType, ContentType = ContentType.Episode, ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), EpisodeNumber = p.EpisodeNumber, @@ -311,7 +312,7 @@ private async Task> GetMoviesContent(IMediaServe private HashSet GetSeriesContent(IMediaServerContentRepository repository, bool test) where T : class, IMediaServerContent { var content = repository.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).AsNoTracking(); - + HashSet episodesToSend; if (test) { @@ -443,7 +444,7 @@ private async Task BuildHtml(ICollection movies, if (movies.Any() && !settings.DisableMovies) { - sb.Append("

New Movies



"); + sb.Append($"

{Texts.NewMovies}



"); sb.Append( ""); sb.Append(""); @@ -460,7 +461,7 @@ private async Task BuildHtml(ICollection movies, if (episodes.Any() && !settings.DisableTv) { - sb.Append("

New TV



"); + sb.Append($"

{Texts.NewTV}



"); sb.Append( "
"); sb.Append(""); @@ -478,7 +479,7 @@ private async Task BuildHtml(ICollection movies, if (albums.Any() && !settings.DisableMusic) { - sb.Append("

New Albums



"); + sb.Append($"

{Texts.NewAlbums}



"); sb.Append( "
"); sb.Append(""); @@ -602,7 +603,7 @@ private void CreateMovieHtmlContent(MovieResponseDto info, string mediaurl) if (info.Genres.Any()) { - AddGenres($"Genres: {string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray())}"); + AddGenres($"{Texts.GenresLabel} {string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray())}"); } } @@ -638,7 +639,7 @@ private void CreateAlbumHtmlContent(AlbumLookup info) } AddParagraph(summary); - AddGenres($"Type: {info.albumType}"); + AddGenres($"{Texts.AlbumTypeLabel} {info.albumType}"); } private async Task ProcessTv(IEnumerable episodes, string languageCode) @@ -740,7 +741,7 @@ private async Task ProcessTv(IEnumerable episodes, string l var orderedEpisodes = epInformation.Episodes.OrderBy(x => x.EpisodeNumber).ToList(); var episodeString = StringHelper.BuildEpisodeList(orderedEpisodes.Select(x => x.EpisodeNumber)); var episodeAirDate = epInformation.EpisodeAirDate; - finalsb.Append($"Season: {epInformation.SeasonNumber} - Episodes: {episodeString} {episodeAirDate}"); + finalsb.Append($"{Texts.SeasonLabel} {epInformation.SeasonNumber} - {Texts.EpisodesLabel} {episodeString} {episodeAirDate}"); finalsb.Append("
"); } @@ -792,7 +793,7 @@ private void AddTvEpisodesSummaryGenres(string episodes, TvInfo tvInfo) if (tvInfo.genres.Any()) { - AddGenres($"Genres: {string.Join(", ", tvInfo.genres.Select(x => x.name.ToString()).ToArray())}"); + AddGenres($"{Texts.GenresLabel} {string.Join(", ", tvInfo.genres.Select(x => x.name.ToString()).ToArray())}"); } } diff --git a/src/Ombi.Settings/Ombi.Settings.csproj b/src/Ombi.Settings/Ombi.Settings.csproj index b39c123e2..4b3aa4c60 100644 --- a/src/Ombi.Settings/Ombi.Settings.csproj +++ b/src/Ombi.Settings/Ombi.Settings.csproj @@ -18,6 +18,7 @@ + diff --git a/src/Ombi.Settings/Settings/Models/OmbiSettings.cs b/src/Ombi.Settings/Settings/Models/OmbiSettings.cs index ba460a2bd..e224b5c70 100644 --- a/src/Ombi.Settings/Settings/Models/OmbiSettings.cs +++ b/src/Ombi.Settings/Settings/Models/OmbiSettings.cs @@ -1,7 +1,10 @@ -namespace Ombi.Settings.Settings.Models +using Ombi.I18n.Resources; +using System.Globalization; +namespace Ombi.Settings.Settings.Models { public class OmbiSettings : Settings { + private string defaultLanguageCode = "en"; public string BaseUrl { get; set; } public bool CollectAnalyticData { get; set; } public bool Wizard { get; set; } @@ -9,7 +12,14 @@ public class OmbiSettings : Settings public bool DoNotSendNotificationsForAutoApprove { get; set; } public bool HideRequestsUsers { get; set; } public bool DisableHealthChecks { get; set; } - public string DefaultLanguageCode { get; set; } = "en"; + public string DefaultLanguageCode + { + get => defaultLanguageCode; + set { + defaultLanguageCode = value; + Texts.Culture = new CultureInfo(value); + } + } public bool AutoDeleteAvailableRequests { get; set; } public int AutoDeleteAfterDays { get; set; } public Branch Branch { get; set; } From c862b02e260c8546408c1847e7455775c2f52921 Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Wed, 19 Jan 2022 13:13:33 +0100 Subject: [PATCH 19/21] Generate file in English --- src/Ombi.I18n/Ombi.I18n.csproj | 15 +++++++- src/Ombi.I18n/Resources/Texts.Designer.cs | 42 +++++++++++------------ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/Ombi.I18n/Ombi.I18n.csproj b/src/Ombi.I18n/Ombi.I18n.csproj index 773215530..f44037974 100644 --- a/src/Ombi.I18n/Ombi.I18n.csproj +++ b/src/Ombi.I18n/Ombi.I18n.csproj @@ -13,5 +13,18 @@ Always - + + + + True + True + Texts.resx + + + + + PublicResXFileCodeGenerator + Texts.Designer.cs + + \ No newline at end of file diff --git a/src/Ombi.I18n/Resources/Texts.Designer.cs b/src/Ombi.I18n/Resources/Texts.Designer.cs index 0f83e8de7..2f589c022 100644 --- a/src/Ombi.I18n/Resources/Texts.Designer.cs +++ b/src/Ombi.I18n/Resources/Texts.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // -// Ce code a été généré par un outil. -// Version du runtime :4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si -// le code est régénéré. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -13,12 +13,12 @@ namespace Ombi.I18n.Resources { /// - /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées. + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder - // à l'aide d'un outil, tel que ResGen ou Visual Studio. - // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen - // avec l'option /str ou régénérez votre projet VS. + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] @@ -33,7 +33,7 @@ internal Texts() { } /// - /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe. + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ internal Texts() { } /// - /// Remplace la propriété CurrentUICulture du thread actuel pour toutes - /// les recherches de ressources à l'aide de cette classe de ressource fortement typée. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Globalization.CultureInfo Culture { @@ -61,7 +61,7 @@ internal Texts() { } /// - /// Recherche une chaîne localisée semblable à Type:. + /// Looks up a localized string similar to Type:. /// public static string AlbumTypeLabel { get { @@ -70,7 +70,7 @@ public static string AlbumTypeLabel { } /// - /// Recherche une chaîne localisée semblable à Episodes:. + /// Looks up a localized string similar to Episodes:. /// public static string EpisodesLabel { get { @@ -79,7 +79,7 @@ public static string EpisodesLabel { } /// - /// Recherche une chaîne localisée semblable à Genres:. + /// Looks up a localized string similar to Genres:. /// public static string GenresLabel { get { @@ -88,7 +88,7 @@ public static string GenresLabel { } /// - /// Recherche une chaîne localisée semblable à New Albums. + /// Looks up a localized string similar to New Albums. /// public static string NewAlbums { get { @@ -97,7 +97,7 @@ public static string NewAlbums { } /// - /// Recherche une chaîne localisée semblable à New Movies. + /// Looks up a localized string similar to New Movies. /// public static string NewMovies { get { @@ -106,7 +106,7 @@ public static string NewMovies { } /// - /// Recherche une chaîne localisée semblable à New TV. + /// Looks up a localized string similar to New TV. /// public static string NewTV { get { @@ -115,7 +115,7 @@ public static string NewTV { } /// - /// Recherche une chaîne localisée semblable à Powered by. + /// Looks up a localized string similar to Powered by. /// public static string PoweredBy { get { @@ -124,7 +124,7 @@ public static string PoweredBy { } /// - /// Recherche une chaîne localisée semblable à Season:. + /// Looks up a localized string similar to Season:. /// public static string SeasonLabel { get { @@ -133,7 +133,7 @@ public static string SeasonLabel { } /// - /// Recherche une chaîne localisée semblable à Unsubscribe. + /// Looks up a localized string similar to Unsubscribe. /// public static string Unsubscribe { get { From 6b68c86705c668169433628d2a46369bc5ac3bca Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Tue, 1 Feb 2022 11:27:03 +0100 Subject: [PATCH 20/21] Fix unsubscribe text unlocalized by messy merge --- src/Ombi.Notifications.Templates/NewsletterTemplate.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ombi.Notifications.Templates/NewsletterTemplate.cs b/src/Ombi.Notifications.Templates/NewsletterTemplate.cs index 90b5a217c..9d3b1632a 100644 --- a/src/Ombi.Notifications.Templates/NewsletterTemplate.cs +++ b/src/Ombi.Notifications.Templates/NewsletterTemplate.cs @@ -44,7 +44,7 @@ public string LoadTemplate(string subject, string intro, string tableHtml, strin sb.Replace(DateKey, DateTime.Now.ToString("f")); sb.Replace(Logo, string.IsNullOrEmpty(logo) ? OmbiLogo : logo); sb.Replace(Unsubscribe, string.IsNullOrEmpty(unsubscribeLink) ? string.Empty : unsubscribeLink); - sb.Replace(UnsubscribeText, string.IsNullOrEmpty(unsubscribeLink) ? string.Empty : "Unsubscrible"); + sb.Replace(UnsubscribeText, string.IsNullOrEmpty(unsubscribeLink) ? string.Empty : Texts.Unsubscribe); sb.Replace(PoweredByText, Texts.PoweredBy); return sb.ToString(); From 47d2a12a8db61fabb5ea3cc50d31eea63b0a365d Mon Sep 17 00:00:00 2001 From: Florian Dupret <34862846+sephrat@users.noreply.github.com> Date: Tue, 1 Feb 2022 11:27:59 +0100 Subject: [PATCH 21/21] Fix indentation --- src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 9dc6c64a6..83788f1b4 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs @@ -265,7 +265,7 @@ private void AddToRecentlyAddedLog(ICollection episodes, recentlyAddedLog.Add(new RecentlyAddedLog { AddedAt = DateTime.Now, - Type = p.Series.RecentlyAddedType, + Type = p.Series.RecentlyAddedType, ContentType = ContentType.Episode, ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), EpisodeNumber = p.EpisodeNumber, @@ -312,7 +312,7 @@ private async Task> GetMoviesContent(IMediaServe private HashSet GetSeriesContent(IMediaServerContentRepository repository, bool test) where T : class, IMediaServerContent { var content = repository.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).AsNoTracking(); - + HashSet episodesToSend; if (test) {