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..3cabfa438 100644 --- a/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs +++ b/src/Ombi.Core.Tests/Rule/Request/ExistingPlexRequestRuleTests.cs @@ -182,11 +182,11 @@ namespace Ombi.Core.Tests.Rule.Request { new PlexServerContent { - Type = PlexMediaTypeEntity.Show, + Type = MediaType.Series, 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..0e455418a 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 @@ namespace Ombi.Core.Tests.Rule.Search 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] @@ -44,66 +47,6 @@ namespace Ombi.Core.Tests.Rule.Search Assert.True(search.Available); } - [Test] - public async Task Movie_Has_Custom_Url_When_Specified_In_Settings() - { - SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings - { - Enable = true, - Servers = new List - { - new EmbyServers - { - ServerHostname = "http://test.com/", - ServerId = "8" - } - } - }); - ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny())).ReturnsAsync(new EmbyContent - { - ProviderId = "123", - EmbyId = 1.ToString(), - }); - var search = new SearchMovieViewModel() - { - TheMovieDbId = "123", - }; - var result = await Rule.Execute(search); - - Assert.True(result.Success); - Assert.That(search.EmbyUrl, Is.EqualTo("http://test.com/web/index.html#!/item?id=1&serverId=8")); - } - - [Test] - public async Task Movie_Uses_Default_Url_When() - { - SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new EmbySettings - { - Enable = true, - Servers = new List - { - new EmbyServers - { - ServerHostname = string.Empty, - ServerId = "8" - } - } - }); - ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny())).ReturnsAsync(new EmbyContent - { - ProviderId = "123", - EmbyId = 1.ToString() - }); - var search = new SearchMovieViewModel() - { - TheMovieDbId = "123", - }; - var result = await Rule.Execute(search); - - Assert.True(result.Success); - Assert.That(search.EmbyUrl, Is.EqualTo("https://app.emby.media/web/index.html#!/item?id=1&serverId=8")); - } - [Test] public async Task Movie_ShouldBe_NotAvailable_WhenNotFoundInEmby() { diff --git a/src/Ombi.Core.Tests/Rule/Search/JellyfinAvailabilityRuleTests.cs b/src/Ombi.Core.Tests/Rule/Search/JellyfinAvailabilityRuleTests.cs index 1b838f102..b733b0b2b 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 @@ namespace Ombi.Core.Tests.Rule.Search 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] @@ -44,36 +47,6 @@ namespace Ombi.Core.Tests.Rule.Search Assert.True(search.Available); } - [Test] - public async Task Movie_Has_Custom_Url_When_Specified_In_Settings() - { - SettingsMock.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new JellyfinSettings - { - Enable = true, - Servers = new List - { - new JellyfinServers - { - ServerHostname = "http://test.com/", - ServerId = "8" - } - } - }); - ContextMock.Setup(x => x.GetByTheMovieDbId(It.IsAny())).ReturnsAsync(new JellyfinContent - { - ProviderId = "123", - JellyfinId = 1.ToString(), - }); - var search = new SearchMovieViewModel() - { - TheMovieDbId = "123", - }; - var result = await Rule.Execute(search); - - Assert.True(result.Success); - Assert.That(search.JellyfinUrl, Is.EqualTo("http://test.com/web/index.html#!/details?id=1&serverId=8")); - } - [Test] public async Task Movie_Uses_Default_Url_When() { 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 @@ namespace Ombi.Core.Engine 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 @@ namespace Ombi.Core.Engine 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 @@ namespace Ombi.Core.Engine { continue; } - if (p.Type == PlexMediaTypeEntity.Movie) + if (p.Type == MediaType.Movie) { recentlyAddedLog.Add(new RecentlyAddedLog { @@ -114,7 +114,7 @@ namespace Ombi.Core.Engine { continue; } - if (e.Type == EmbyMediaType.Movie) + if (e.Type == MediaType.Movie) { recentlyAddedLog.Add(new RecentlyAddedLog { @@ -152,7 +152,7 @@ namespace Ombi.Core.Engine { 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 @@ namespace Ombi.Core.Rule.Rules.Request { 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/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 @@ namespace Ombi.Core.Rule.Rules.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 @@ namespace Ombi.Core.Rule.Rules.Search log.LogError(e, "Exception thrown when attempting to check if something is available"); } - if (epExists != null) - { - episode.Available = true; - } - } - 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..e7a629854 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) @@ -64,19 +67,7 @@ namespace Ombi.Core.Rule.Rules.Search if (item != null) { obj.Available = true; - var s = await EmbySettings.GetSettingsAsync(); - if (s.Enable) - { - var server = s.Servers.FirstOrDefault(); - if ((server?.ServerHostname ?? string.Empty).HasValue()) - { - obj.EmbyUrl = EmbyHelper.GetEmbyMediaUrl(item.EmbyId, server?.ServerId, server?.ServerHostname); - } - else - { - obj.EmbyUrl = EmbyHelper.GetEmbyMediaUrl(item.EmbyId, server?.ServerId, null); - } - } + obj.EmbyUrl = item.Url; if (obj.Type == RequestType.TvShow) { @@ -89,7 +80,7 @@ namespace Ombi.Core.Rule.Rules.Search { 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..95a2da80b 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) @@ -78,20 +81,7 @@ namespace Ombi.Core.Rule.Rules.Search useTheMovieDb = true; } obj.Available = true; - var s = await JellyfinSettings.GetSettingsAsync(); - if (s.Enable) - { - var server = s.Servers.FirstOrDefault(x => x.ServerHostname != null); - if ((server?.ServerHostname ?? string.Empty).HasValue()) - { - obj.JellyfinUrl = JellyfinHelper.GetJellyfinMediaUrl(item.JellyfinId, server?.ServerId, server?.ServerHostname); - } - else - { - var firstServer = s.Servers?.FirstOrDefault(); - obj.JellyfinUrl = JellyfinHelper.GetJellyfinMediaUrl(item.JellyfinId, firstServer.ServerId, firstServer.FullUri); - } - } + obj.JellyfinUrl = item.Url; if (obj.Type == RequestType.TvShow) { @@ -104,7 +94,7 @@ namespace Ombi.Core.Rule.Rules.Search { 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/PlexAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs index 42e97f5f7..4c05e0fe1 100644 --- a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs @@ -33,7 +33,7 @@ namespace Ombi.Core.Rule.Rules.Search var useId = false; var useTvDb = false; - PlexMediaTypeEntity type = ConvertType(obj.Type); + MediaType type = ConvertType(obj.Type); if (obj.ImdbId.HasValue()) { @@ -90,9 +90,17 @@ namespace Ombi.Core.Rule.Rules.Search useTheMovieDb = true; } obj.Available = true; - obj.PlexUrl = PlexHelper.BuildPlexMediaUrl(item.Url, host); + if (item.Url.StartsWith("http")) + { + obj.PlexUrl = item.Url; + } + else + { + // legacy content + obj.PlexUrl = PlexHelper.BuildPlexMediaUrl(item.Url, host); + } obj.Quality = item.Quality; - + if (obj.Type == RequestType.TvShow) { var search = (SearchTvShowViewModel)obj; @@ -115,12 +123,12 @@ namespace Ombi.Core.Rule.Rules.Search 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.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 @@ namespace Ombi.Helpers 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.Notifications.Templates/NewsletterTemplate.cs b/src/Ombi.Notifications.Templates/NewsletterTemplate.cs index ef31dfc4c..aeaeb40c6 100644 --- a/src/Ombi.Notifications.Templates/NewsletterTemplate.cs +++ b/src/Ombi.Notifications.Templates/NewsletterTemplate.cs @@ -30,6 +30,7 @@ namespace Ombi.Notifications.Templates private const string TableLocation = "{@RECENTLYADDED}"; private const string IntroText = "{@INTRO}"; private const string Unsubscribe = "{@UNSUBSCRIBE}"; + private const string UnsubscribeText = "{@UNSUBSCRIBETEXT}"; public string LoadTemplate(string subject, string intro, string tableHtml, string logo, string unsubscribeLink) @@ -41,6 +42,7 @@ namespace Ombi.Notifications.Templates 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"); return sb.ToString(); } diff --git a/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html b/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html index 71666ba67..befb4dfa3 100644 --- a/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html +++ b/src/Ombi.Notifications.Templates/Templates/NewsletterTemplate.html @@ -453,7 +453,7 @@ - Unsubscribe + {@UNSUBSCRIBETEXT} 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 @@ namespace Ombi.Schedule.Jobs.Emby 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/Emby/EmbyContentSync.cs b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs index 154ae784f..cb7eaefd3 100644 --- a/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Emby/EmbyContentSync.cs @@ -16,7 +16,7 @@ using Ombi.Schedule.Jobs.Ombi; 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,10 +165,10 @@ namespace Ombi.Schedule.Jobs.Emby 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 + AddedAt = DateTime.UtcNow, }); } else @@ -255,10 +255,10 @@ namespace Ombi.Schedule.Jobs.Emby 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, + AddedAt = DateTime.UtcNow }); } else 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 @@ namespace Ombi.Schedule.Jobs.Jellyfin 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/Jellyfin/JellyfinContentSync.cs b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs index e8de12bd2..60ee42210 100644 --- a/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Jellyfin/JellyfinContentSync.cs @@ -14,7 +14,7 @@ using Ombi.Schedule.Jobs.Ombi; 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 @@ namespace Ombi.Schedule.Jobs.Jellyfin 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,10 +223,10 @@ namespace Ombi.Schedule.Jobs.Jellyfin ImdbId = movieInfo.ProviderIds.Imdb, TheMovieDbId = movieInfo.ProviderIds?.Tmdb, Title = movieInfo.Name, - Type = JellyfinMediaType.Movie, + Type = MediaType.Movie, JellyfinId = movieInfo.Id, Url = JellyfinHelper.GetJellyfinMediaUrl(movieInfo.Id, server?.ServerId, server.ServerHostname), - AddedAt = DateTime.UtcNow, + AddedAt = DateTime.UtcNow }); } else diff --git a/src/Ombi.Schedule/Jobs/Ombi/HtmlTemplateGenerator.cs b/src/Ombi.Schedule/Jobs/Ombi/HtmlTemplateGenerator.cs index 54d1d1133..9d49fe2f1 100644 --- a/src/Ombi.Schedule/Jobs/Ombi/HtmlTemplateGenerator.cs +++ b/src/Ombi.Schedule/Jobs/Ombi/HtmlTemplateGenerator.cs @@ -5,7 +5,8 @@ namespace Ombi.Schedule.Jobs.Ombi { public abstract class HtmlTemplateGenerator { - protected virtual void AddBackgroundInsideTable(StringBuilder sb, string url) + protected StringBuilder sb; + protected virtual void AddBackgroundInsideTable(string url) { sb.Append(""); sb.AppendFormat("", url); @@ -14,14 +15,14 @@ namespace Ombi.Schedule.Jobs.Ombi sb.Append("
"); } - protected virtual void AddPosterInsideTable(StringBuilder sb, string url) + protected virtual void AddPosterInsideTable(string url) { sb.Append(""); 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 @@ namespace Ombi.Schedule.Jobs.Ombi sb.Append(""); } - protected virtual void AddInfoTable(StringBuilder sb) + protected virtual void AddInfoTable() { sb.Append( ""); @@ -645,7 +485,7 @@ namespace Ombi.Schedule.Jobs.Ombi sb.Append(""); @@ -656,10 +496,10 @@ namespace Ombi.Schedule.Jobs.Ombi return sb.ToString(); } - private async Task ProcessPlexMovies(IQueryable plexContentToSend, StringBuilder sb, 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); @@ -668,23 +508,23 @@ namespace Ombi.Schedule.Jobs.Ombi continue; } var info = await _movieApi.GetMovieInformationWithExtraInfo(movieDbId, defaultLanguageCode); - var mediaurl = PlexHelper.BuildPlexMediaUrl(content.Url, mediaServerUrl); + var mediaurl = content.Url; if (info == null) { continue; } try { - CreateMovieHtmlContent(sb, info, mediaurl); + CreateMovieHtmlContent(info, mediaurl); count += 1; } 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 { - EndLoopHtml(sb); + EndLoopHtml(); } if (count == 2) @@ -695,7 +535,7 @@ namespace Ombi.Schedule.Jobs.Ombi } } } - private async Task ProcessAlbums(HashSet albumsToSend, StringBuilder sb) + private async Task ProcessAlbums(HashSet albumsToSend) { var settings = await _lidarrSettings.GetSettingsAsync(); int count = 0; @@ -709,7 +549,7 @@ namespace Ombi.Schedule.Jobs.Ombi } try { - CreateAlbumHtmlContent(sb, info); + CreateAlbumHtmlContent(info); count += 1; } catch (Exception e) @@ -718,60 +558,7 @@ namespace Ombi.Schedule.Jobs.Ombi } finally { - EndLoopHtml(sb); - } - - if (count == 2) - { - count = 0; - sb.Append(""); - sb.Append(""); - } - } - } - - 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); + EndLoopHtml(); } if (count == 2) @@ -783,66 +570,13 @@ namespace Ombi.Schedule.Jobs.Ombi } } - private async Task ProcessJellyfinMovies(IQueryable embyContent, StringBuilder sb, string defaultLangaugeCode, string customUrl) + private void CreateMovieHtmlContent(MovieResponseDto info, string mediaurl) { - 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; - } + AddBackgroundInsideTable($"https://image.tmdb.org/t/p/w1280/{info.BackdropPath}"); + AddPosterInsideTable($"https://image.tmdb.org/t/p/original{info.PosterPath}"); - 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}"); - AddPosterInsideTable(sb, $"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 @@ -856,7 +590,7 @@ namespace Ombi.Schedule.Jobs.Ombi // 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) @@ -864,16 +598,15 @@ namespace Ombi.Schedule.Jobs.Ombi 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; @@ -881,21 +614,21 @@ namespace Ombi.Schedule.Jobs.Ombi { 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) @@ -903,29 +636,28 @@ namespace Ombi.Schedule.Jobs.Ombi summary = summary.Remove(280); summary = summary + "...

"; } - AddParagraph(sb, summary); + AddParagraph(summary); - AddGenres(sb, $"Type: {info.albumType}"); + AddGenres($"Type: {info.albumType}"); } - private async Task ProcessPlexTv(HashSet plexContent, StringBuilder sb, string languageCode, string serverHostname) + private async Task ProcessTv(IEnumerable episodes, string languageCode) { - 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.Series.Key); - if (alreadyAdded != null) + var existingSeries = episode.SeriesIsIn(series); + if (existingSeries != null) { - var episodeExists = alreadyAdded.Episodes.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.Series); + episode.Series.Episodes = new List { episode }; + series.Add(episode.Series); } } @@ -979,17 +711,17 @@ namespace Ombi.Schedule.Jobs.Ombi 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(t.Url, banner); + AddInfoTable(); - AddTvTitle(sb, info, tvInfo); + AddTvTitle(info, tvInfo); // Group by the season number var results = t.Episodes.GroupBy(p => p.SeasonNumber, @@ -1012,7 +744,7 @@ namespace Ombi.Schedule.Jobs.Ombi finalsb.Append("
"); } - AddTvEpisodesSummaryGenres(sb, finalsb.ToString(), tvInfo); + AddTvEpisodesSummaryGenres(finalsb.ToString(), tvInfo); } catch (Exception e) @@ -1021,215 +753,7 @@ namespace Ombi.Schedule.Jobs.Ombi } finally { - EndLoopHtml(sb); - count += 1; - } - - if (count == 2) - { - count = 0; - sb.Append("
"); - sb.Append(""); - } - } - } - - - - 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.Series.EmbyId); - if (alreadyAdded != null) - { - alreadyAdded.Episodes.Add(episode); - } - else - { - episode.Series.Episodes = new List - { - episode - }; - series.Add(episode.Series); - } - } - - 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.Series.JellyfinId); - if (alreadyAdded != null) - { - alreadyAdded.Episodes.Add(episode); - } - else - { - episode.Series.Episodes = new List - { - episode - }; - series.Add(episode.Series); - } - } - - 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); + EndLoopHtml(); count += 1; } @@ -1242,7 +766,7 @@ namespace Ombi.Schedule.Jobs.Ombi } } - 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) @@ -1253,10 +777,10 @@ namespace Ombi.Schedule.Jobs.Ombi { 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) @@ -1264,15 +788,15 @@ namespace Ombi.Schedule.Jobs.Ombi 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/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 @@ namespace Ombi.Schedule.Jobs.Ombi { // 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 @@ namespace Ombi.Schedule.Jobs.Ombi 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 @@ namespace Ombi.Schedule.Jobs.Ombi 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 @@ namespace Ombi.Schedule.Jobs.Ombi 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 @@ namespace Ombi.Schedule.Jobs.Ombi 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/PlexAvailabilityChecker.cs b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs index 7a05f794b..74dc4aa96 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexAvailabilityChecker.cs @@ -86,7 +86,7 @@ namespace Ombi.Schedule.Jobs.Plex 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 @@ namespace Ombi.Schedule.Jobs.Plex { // 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.Series.Title == child.Title); } diff --git a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs index 3289c5a24..df96457d0 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexContentSync.cs @@ -226,7 +226,7 @@ namespace Ombi.Schedule.Jobs.Plex 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)); } } @@ -301,7 +301,7 @@ namespace Ombi.Schedule.Jobs.Plex { 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,9 +349,9 @@ namespace Ombi.Schedule.Jobs.Plex 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), + Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, movie.ratingKey, servers.ServerHostname), Seasons = new List(), Quality = movie.Media?.FirstOrDefault()?.videoResolution ?? string.Empty }; @@ -411,7 +411,7 @@ namespace Ombi.Schedule.Jobs.Plex // Let's try and match var existingContent = await Repo.GetFirstContentByCustom(x => 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); @@ -463,7 +463,7 @@ namespace Ombi.Schedule.Jobs.Plex Repo.DeleteWithoutSave(existingContent); // Because we have changed the rating key, we need to change all children too - var episodeToChange = Repo.GetAllEpisodes().Where(x => x.GrandparentKey == oldKey); + var episodeToChange = Repo.GetAllEpisodes().Cast().Where(x => x.GrandparentKey == oldKey); if (episodeToChange.Any()) { foreach (var e in episodeToChange) @@ -553,9 +553,9 @@ namespace Ombi.Schedule.Jobs.Plex AddedAt = DateTime.Now, Key = show.ratingKey, ReleaseYear = show.year.ToString(), - Type = PlexMediaTypeEntity.Show, + Type = MediaType.Series, Title = show.title, - Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, show.ratingKey), + Url = PlexHelper.GetPlexMediaUrl(servers.MachineIdentifier, show.ratingKey, servers.ServerHostname), Seasons = new List() }; await GetProviderIds(showMetadata, item); @@ -567,19 +567,19 @@ namespace Ombi.Schedule.Jobs.Plex if (item.ImdbId.HasValue()) { existingImdb = await Repo.GetAll().AnyAsync(x => - 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..4a088ca7b 100644 --- a/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs +++ b/src/Ombi.Schedule/Jobs/Plex/PlexEpisodeSync.cs @@ -113,7 +113,7 @@ namespace Ombi.Schedule.Jobs.Plex { 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/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 @@ namespace Ombi.Store.Context 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 348573f28..08118b6df 100644 --- a/src/Ombi.Store/Entities/EmbyContent.cs +++ b/src/Ombi.Store/Entities/EmbyContent.cs @@ -32,40 +32,13 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Ombi.Store.Entities { [Table("EmbyContent")] - public class EmbyContent : Entity + public class EmbyContent : MediaServerContent { - public string Title { get; set; } - /// - /// OBSOLETE, Cannot delete due to DB migration issues with SQLite - /// + [Obsolete("Cannot delete due to DB migration issues with SQLite")] public string ProviderId { get; set; } public string EmbyId { get; set; } - public EmbyMediaType 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); + public override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Emby; } - 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..97fdb09b1 100644 --- a/src/Ombi.Store/Entities/EmbyEpisode.cs +++ b/src/Ombi.Store/Entities/EmbyEpisode.cs @@ -26,18 +26,16 @@ #endregion using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; -using Microsoft.EntityFrameworkCore.Metadata; +using System.Linq; namespace Ombi.Store.Entities { [Table("EmbyEpisode")] - public class EmbyEpisode : Entity + 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 +45,23 @@ namespace Ombi.Store.Entities public string TvDbId { get; set; } public string ImdbId { get; set; } public string TheMovieDbId { get; set; } + [NotMapped] + public EmbyContent EmbySeries + { + get => (EmbyContent)Series; + set => Series = value; + } + + public override IMediaServerContent SeriesIsIn(ICollection content) + { + 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); + } - public EmbyContent Series { get; set; } } } \ No newline at end of file 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 new file mode 100644 index 000000000..25e4d5f50 --- /dev/null +++ b/src/Ombi.Store/Entities/IMediaServerContent.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities +{ + public interface IMediaServerContent: IEntity + { + 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 RecentlyAddedType RecentlyAddedType{ get; } + + 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 IMediaServerContent SeriesIsIn(ICollection content); + public bool IsIn(IMediaServerContent content); + } + + 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..b2bb63959 100644 --- a/src/Ombi.Store/Entities/JellyfinContent.cs +++ b/src/Ombi.Store/Entities/JellyfinContent.cs @@ -32,40 +32,14 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Ombi.Store.Entities { [Table("JellyfinContent")] - public class JellyfinContent : Entity + public class JellyfinContent : MediaServerContent { - public string Title { get; set; } - /// - /// OBSOLETE, Cannot delete due to DB migration issues with SQLite - /// + + [Obsolete("Cannot delete due to DB migration issues with SQLite")] public string ProviderId { get; set; } public string JellyfinId { get; set; } - public JellyfinMediaType 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); + public override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Jellyfin; } - 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..1c0ac423e 100644 --- a/src/Ombi.Store/Entities/JellyfinEpisode.cs +++ b/src/Ombi.Store/Entities/JellyfinEpisode.cs @@ -26,18 +26,17 @@ #endregion using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; using Microsoft.EntityFrameworkCore.Metadata; namespace Ombi.Store.Entities { [Table("JellyfinEpisode")] - public class JellyfinEpisode : Entity + 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 +46,22 @@ namespace Ombi.Store.Entities 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; + } + + public override IMediaServerContent SeriesIsIn(ICollection content) + { + 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 new file mode 100644 index 000000000..3bccfea06 --- /dev/null +++ b/src/Ombi.Store/Entities/MediaServerContent.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.DataAnnotations.Schema; +using Ombi.Store.Repository; + +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); + + [NotMapped] + public abstract RecentlyAddedType RecentlyAddedType { get; } + } + + 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; } + + 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 3acca8f3b..ac482d7ac 100644 --- a/src/Ombi.Store/Entities/PlexEpisode.cs +++ b/src/Ombi.Store/Entities/PlexEpisode.cs @@ -1,30 +1,38 @@ -using System.ComponentModel.DataAnnotations.Schema; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; namespace Ombi.Store.Entities { [Table("PlexEpisode")] - public class PlexEpisode : Entity + 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; } + [NotMapped] + public PlexServerContent PlexSeries + { + get => (PlexServerContent)Series; + set => Series = value; + } + public override IMediaServerContent SeriesIsIn(ICollection content) + { + return content.OfType().FirstOrDefault( + x => x.Key == this.PlexSeries.Key); + } + + public override bool IsIn(IMediaServerContent content) + { + return content.Episodes.Cast().Any(x => x.Key == this.Key); + } - public PlexServerContent Series { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Store/Entities/PlexServerContent.cs b/src/Ombi.Store/Entities/PlexServerContent.cs index f8e0e01d4..cba02c68c 100644 --- a/src/Ombi.Store/Entities/PlexServerContent.cs +++ b/src/Ombi.Store/Entities/PlexServerContent.cs @@ -32,37 +32,20 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Ombi.Store.Entities { [Table("PlexServerContent")] - public class PlexServerContent : Entity + 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 PlexMediaTypeEntity Type { get; set; } - - public string Url { 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 override RecentlyAddedType RecentlyAddedType => RecentlyAddedType.Plex; } [Table("PlexSeasonsContent")] @@ -73,10 +56,4 @@ namespace Ombi.Store.Entities 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/EmbyContentRepository.cs b/src/Ombi.Store/Repository/EmbyContentRepository.cs index f8743e30f..19bab7f76 100644 --- a/src/Ombi.Store/Repository/EmbyContentRepository.cs +++ b/src/Ombi.Store/Repository/EmbyContentRepository.cs @@ -35,17 +35,13 @@ using Ombi.Store.Entities; 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,20 +65,20 @@ namespace Ombi.Store.Repository return await Db.EmbyContent./*Include(x => x.Seasons).*/FirstOrDefaultAsync(x => x.EmbyId == embyId); } - public async Task Update(EmbyContent existingContent) + public override async Task Update(IMediaServerContent existingContent) { - Db.EmbyContent.Update(existingContent); + Db.EmbyContent.Update((EmbyContent)existingContent); await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public override IQueryable GetAllEpisodes() { return Db.EmbyEpisode.AsQueryable(); } - public async Task Add(EmbyEpisode content) + public override async Task Add(IMediaServerEpisode content) { - await Db.EmbyEpisode.AddAsync(content); + await Db.EmbyEpisode.AddAsync((EmbyEpisode)content); await InternalSaveChanges(); return content; } @@ -91,16 +87,17 @@ namespace Ombi.Store.Repository 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(content); + Db.EmbyEpisode.AddRange((IEnumerable)content); await InternalSaveChanges(); } - public void UpdateWithoutSave(EmbyContent existingContent) + public override void UpdateWithoutSave(IMediaServerContent existingContent) { - Db.EmbyContent.Update(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 a893e9aca..c171fef20 100644 --- a/src/Ombi.Store/Repository/IEmbyContentRepository.cs +++ b/src/Ombi.Store/Repository/IEmbyContentRepository.cs @@ -6,19 +6,16 @@ using Ombi.Store.Entities; 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/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 @@ using Ombi.Store.Entities; 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 @@ namespace Ombi.Store.Repository 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 ff1f2d7dc..30efa1a17 100644 --- a/src/Ombi.Store/Repository/IJellyfinContentRepository.cs +++ b/src/Ombi.Store/Repository/IJellyfinContentRepository.cs @@ -6,19 +6,16 @@ using Ombi.Store.Entities; 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..73cc00fde --- /dev/null +++ b/src/Ombi.Store/Repository/IMediaServerContentRepository.cs @@ -0,0 +1,18 @@ +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 : 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/IPlexContentRepository.cs b/src/Ombi.Store/Repository/IPlexContentRepository.cs index 38c013cb1..f3c6d0ae2 100644 --- a/src/Ombi.Store/Repository/IPlexContentRepository.cs +++ b/src/Ombi.Store/Repository/IPlexContentRepository.cs @@ -8,23 +8,18 @@ using Ombi.Store.Entities; 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, PlexMediaTypeEntity plexType); + Task GetByType(string providerId, ProviderType type, MediaType mediaType); 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 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 @@ using Ombi.Store.Entities; 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 @@ namespace Ombi.Store.Repository 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 2b84adb00..28cdcfae8 100644 --- a/src/Ombi.Store/Repository/JellyfinContentRepository.cs +++ b/src/Ombi.Store/Repository/JellyfinContentRepository.cs @@ -35,17 +35,13 @@ using Ombi.Store.Entities; 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,20 +65,20 @@ namespace Ombi.Store.Repository return await Db.JellyfinContent./*Include(x => x.Seasons).*/FirstOrDefaultAsync(x => x.JellyfinId == jellyfinId); } - public async Task Update(JellyfinContent existingContent) + public override async Task Update(IMediaServerContent existingContent) { - Db.JellyfinContent.Update(existingContent); + Db.JellyfinContent.Update((JellyfinContent)existingContent); await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public override IQueryable GetAllEpisodes() { return Db.JellyfinEpisode.AsQueryable(); } - public async Task Add(JellyfinEpisode content) + public override async Task Add(IMediaServerEpisode content) { - await Db.JellyfinEpisode.AddAsync(content); + await Db.JellyfinEpisode.AddAsync((JellyfinEpisode)content); await InternalSaveChanges(); return content; } @@ -91,16 +87,17 @@ namespace Ombi.Store.Repository 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(content); + Db.JellyfinEpisode.AddRange((IEnumerable)content); await InternalSaveChanges(); } - public void UpdateWithoutSave(JellyfinContent existingContent) + public override void UpdateWithoutSave(IMediaServerContent existingContent) { - Db.JellyfinContent.Update(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..0f458ee2b --- /dev/null +++ b/src/Ombi.Store/Repository/MediaServerRepository.cs @@ -0,0 +1,25 @@ +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); + 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 31b3bad11..b99ba157f 100644 --- a/src/Ombi.Store/Repository/PlexContentRepository.cs +++ b/src/Ombi.Store/Repository/PlexContentRepository.cs @@ -37,17 +37,13 @@ using Ombi.Store.Entities; 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); @@ -79,16 +75,16 @@ namespace Ombi.Store.Repository return null; } - public async Task GetByType(string providerId, ProviderType type, PlexMediaTypeEntity 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; } @@ -114,14 +110,14 @@ namespace Ombi.Store.Repository .FirstOrDefaultAsync(predicate); } - public async Task Update(PlexServerContent existingContent) + public override async Task Update(IMediaServerContent existingContent) { - Db.PlexServerContent.Update(existingContent); + Db.PlexServerContent.Update((PlexServerContent)existingContent); await InternalSaveChanges(); } - public void UpdateWithoutSave(PlexServerContent existingContent) + public override void UpdateWithoutSave(IMediaServerContent existingContent) { - Db.PlexServerContent.Update(existingContent); + Db.PlexServerContent.Update((PlexServerContent)existingContent); } public async Task UpdateRange(IEnumerable existingContent) @@ -130,7 +126,7 @@ namespace Ombi.Store.Repository await InternalSaveChanges(); } - public IQueryable GetAllEpisodes() + public override IQueryable GetAllEpisodes() { return Db.PlexEpisode.Include(x => x.Series).AsQueryable(); } @@ -145,9 +141,9 @@ namespace Ombi.Store.Repository Db.PlexEpisode.Remove(content); } - public async Task Add(PlexEpisode content) + public override async Task Add(IMediaServerEpisode content) { - await Db.PlexEpisode.AddAsync(content); + await Db.PlexEpisode.AddAsync((PlexEpisode)content); await InternalSaveChanges(); return content; } @@ -162,10 +158,11 @@ namespace Ombi.Store.Repository { 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(content); + Db.PlexEpisode.AddRange((IEnumerable)content); await InternalSaveChanges(); } + } } \ No newline at end of file
"); 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(""); @@ -604,7 +458,7 @@ namespace Ombi.Schedule.Jobs.Ombi sb.Append("
"); @@ -59,7 +60,7 @@ namespace Ombi.Schedule.Jobs.Ombi sb.Append("
"); @@ -68,7 +69,7 @@ namespace Ombi.Schedule.Jobs.Ombi sb.Append("
"); @@ -78,7 +79,7 @@ namespace Ombi.Schedule.Jobs.Ombi sb.Append("
"); diff --git a/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs b/src/Ombi.Schedule/Jobs/Ombi/NewsletterJob.cs index 7752d298d..49101c52a 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.External; 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; @@ -74,9 +68,9 @@ namespace Ombi.Schedule.Jobs.Ombi _refreshMetadata = refreshMetadata; } - private readonly IPlexContentRepository _plex; - private readonly IEmbyContentRepository _emby; - private readonly IJellyfinContentRepository _jellyfin; + private readonly IMediaServerContentRepository _plex; + private readonly IMediaServerContentRepository _emby; + private readonly IMediaServerContentRepository _jellyfin; private readonly IRepository _recentlyAddedLog; private readonly IMovieDbApi _movieApi; private readonly ITvMazeApi _tvApi; @@ -122,88 +116,37 @@ namespace Ombi.Schedule.Jobs.Ombi try { + var plexSettings = await _plexSettings.GetSettingsAsync(); + var embySettings = await _embySettings.GetSettingsAsync(); + var jellyfinSettings = await _jellyfinSettings.GetSettingsAsync(); 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); - - var addedLog = _recentlyAddedLog.GetAll().ToList(); - - HashSet addedPlexMovieLogIds, addedEmbyMoviesLogIds, addedJellyfinMoviesLogIds; - HashSet addedAlbumLogIds; - GetRecentlyAddedMoviesData(addedLog, out addedPlexMovieLogIds, out addedEmbyMoviesLogIds, out addedJellyfinMoviesLogIds, out addedAlbumLogIds); - 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); + var moviesContents = new List(); + var seriesContents = new List(); + if (plexSettings.Enable) + { + moviesContents.AddRange(await GetMoviesContent(_plex, test)); + seriesContents.AddRange(GetSeriesContent(_plex, test)); + } + if (embySettings.Enable) + { + 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); - // Filter out the ones that we haven't sent yet - var plexContentLocalDataset = plexContent.Where(x => 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 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()); + var body = await BuildHtml(moviesContents, seriesContents, albumsContents, settings); - // 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 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(), - addedEmbyEpisodesLogIds); - var jellyfinEpisodesToSend = FilterJellyfinEpisodes(_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) + if (body.IsNullOrEmpty()) { - 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 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 lidarr = lidarrContent.OrderByDescending(x => x.AddedAt).Take(10).ToHashSet(); - body = await BuildHtml(plexm, embym, jellyfinm, plext, embyt, jellyfint, lidarr, settings, embySettings, jellyfinSettings, plexSettings); - } - else - { - body = await BuildHtml(plexContentMoviesToSend.AsQueryable(), embyContentMoviesToSend.AsQueryable(), jellyfinContentMoviesToSend.AsQueryable(), plexEpisodesToSend, embyEpisodesToSend, jellyfinEpisodesToSend, lidarrContentAlbumsToSend, settings, embySettings, jellyfinSettings, plexSettings); - if (body.IsNullOrEmpty()) - { - return; - } + return; } if (!test) @@ -223,7 +166,7 @@ namespace Ombi.Schedule.Jobs.Ombi if (!users.Any()) { return; - } + } var messageContent = ParseTemplate(template, customization); var email = new NewsletterTemplate(); @@ -258,84 +201,8 @@ namespace Ombi.Schedule.Jobs.Ombi // 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), - }); - - } - - foreach (var p in plexEpisodesToSend) - { - recentlyAddedLog.Add(new RecentlyAddedLog - { - AddedAt = DateTime.Now, - Type = RecentlyAddedType.Plex, - ContentType = ContentType.Episode, - ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), - EpisodeNumber = p.EpisodeNumber, - SeasonNumber = p.SeasonNumber - }); - } - foreach (var e in embyContentMoviesToSend) - { - if (e.Type == EmbyMediaType.Movie) - { - recentlyAddedLog.Add(new RecentlyAddedLog - { - AddedAt = DateTime.Now, - Type = RecentlyAddedType.Emby, - ContentType = ContentType.Parent, - ContentId = StringHelper.IntParseLinq(e.TheMovieDbId), - }); - } - } - - foreach (var p in embyEpisodesToSend) - { - recentlyAddedLog.Add(new RecentlyAddedLog - { - AddedAt = DateTime.Now, - Type = RecentlyAddedType.Emby, - ContentType = ContentType.Episode, - ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), - EpisodeNumber = p.EpisodeNumber, - SeasonNumber = p.SeasonNumber - }); - } - - foreach (var e in jellyfinContentMoviesToSend) - { - if (e.Type == JellyfinMediaType.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 - { - AddedAt = DateTime.Now, - Type = RecentlyAddedType.Jellyfin, - ContentType = ContentType.Episode, - ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), - EpisodeNumber = p.EpisodeNumber, - SeasonNumber = p.SeasonNumber - }); - } - + AddToRecentlyAddedLog(moviesContents, recentlyAddedLog); + AddToRecentlyAddedLog(seriesContents, recentlyAddedLog); await _recentlyAddedLog.AddRange(recentlyAddedLog); } else @@ -375,79 +242,148 @@ namespace Ombi.Schedule.Jobs.Ombi .SendAsync(NotificationHub.NotificationEvent, "Newsletter Finished"); } - private void GetRecentlyAddedMoviesData(List addedLog, out HashSet addedPlexMovieLogIds, out HashSet addedEmbyMoviesLogIds, out HashSet addedJellyfinMoviesLogIds, out HashSet addedAlbumLogIds) + private void AddToRecentlyAddedLog(ICollection moviesContents, + HashSet recentlyAddedLog) { - 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(); + foreach (var p in moviesContents) + { + recentlyAddedLog.Add(new RecentlyAddedLog + { + AddedAt = DateTime.Now, + Type = p.RecentlyAddedType, + 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.RecentlyAddedType, + ContentType = ContentType.Episode, + ContentId = StringHelper.IntParseLinq(p.Series.TvDbId), + EpisodeNumber = p.EpisodeNumber, + SeasonNumber = p.SeasonNumber + }); + } + } + 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(); } - public static string GenerateUnsubscribeLink(string applicationUrl, string id) + private async Task> GetMoviesContent(IMediaServerContentRepository repository, bool test) where T : class, IMediaServerContent { - if (!applicationUrl.HasValue() || !id.HasValue()) + 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(); + + HashSet moviesToSend; + if (test) { - return string.Empty; + moviesToSend = content.Take(10).ToHashSet(); } - - if (!applicationUrl.EndsWith('/')) + else { - applicationUrl += '/'; + // 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(); } - var b = new UriBuilder($"{applicationUrl}unsubscribe/{id}"); - return b.ToString(); + + _log.LogInformation("Movies to send: {0}", moviesToSend.Count()); + return moviesToSend.DistinctBy(x => x.Id).ToHashSet(); } - private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDbPlex) + private HashSet GetSeriesContent(IMediaServerContentRepository repository, bool test) where T : class, IMediaServerContent { - foreach (var movie in needsMovieDbPlex) + var content = repository.GetAllEpisodes().Include(x => x.Series).OrderByDescending(x => x.Series.AddedAt).AsNoTracking(); + + HashSet episodesToSend; + if (test) { - var id = await _refreshMetadata.GetTheMovieDbId(false, true, null, movie.ImdbId, movie.Title, true); - movie.TheMovieDbId = id.ToString(); + var count = repository.GetAllEpisodes().Count(); + 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); } - var result = needsMovieDbPlex.Where(x => x.HasTheMovieDb && !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); - await UpdateTheMovieDbId(result); - // Filter them out now - return result.ToHashSet(); + _log.LogInformation("Episodes to send: {0}", episodesToSend.Count()); + return episodesToSend; + } + private HashSet GetMusicContent(IExternalRepository repository, bool test) + { + + var lidarrContent = repository.GetAll().AsNoTracking().ToList().Where(x => x.FullyAvailable); - private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDbPlex) + 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; + + } + + public static string GenerateUnsubscribeLink(string applicationUrl, string id) { - foreach (var movie in needsMovieDbPlex) + if (!applicationUrl.HasValue() || !id.HasValue()) { - var id = await _refreshMetadata.GetTheMovieDbId(false, true, null, movie.ImdbId, movie.Title, true); - movie.TheMovieDbId = id.ToString(); + return string.Empty; } - var result = needsMovieDbPlex.Where(x => x.HasTheMovieDb && !addedMovieLogIds.Contains(StringHelper.IntParseLinq(x.TheMovieDbId))); - await UpdateTheMovieDbId(result); - // Filter them out now - return result.ToHashSet(); + if (!applicationUrl.EndsWith('/')) + { + applicationUrl += '/'; + } + var b = new UriBuilder($"{applicationUrl}unsubscribe/{id}"); + return b.ToString(); } - private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDbJellyfin) + private async Task> GetMoviesWithoutId(HashSet addedMovieLogIds, HashSet needsMovieDb, IMediaServerContentRepository repository) where T : class, IMediaServerContent { - foreach (var movie in needsMovieDbJellyfin) + foreach (var movie in needsMovieDb) { 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); + 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) where T : class, IMediaServerContent { foreach (var movie in content) { @@ -455,45 +391,15 @@ namespace Ombi.Schedule.Jobs.Ombi { 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); - } - 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); + repository.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(); + await repository.SaveChangesAsync(); } public async Task Execute(IJobExecutionContext job) @@ -502,43 +408,9 @@ namespace Ombi.Schedule.Jobs.Ombi 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) - { - 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) + private HashSet FilterEpisodes(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); @@ -563,17 +435,13 @@ namespace Ombi.Schedule.Jobs.Ombi 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, - PlexSettings plexSettings) + private async Task BuildHtml(ICollection movies, + IEnumerable episodes, HashSet albums, NewsletterSettings settings) { var ombiSettings = await _ombiSettings.GetSettingsAsync(); - var sb = new StringBuilder(); + 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); - if ((plexMovies.Any() || embyMovies.Any() || jellyfinMovies.Any()) && !settings.DisableMovies) + if (movies.Any() && !settings.DisableMovies) { sb.Append("

New Movies



"); sb.Append( @@ -582,21 +450,7 @@ namespace Ombi.Schedule.Jobs.Ombi 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) - { - await ProcessJellyfinMovies(jellyfinMovies, sb, ombiSettings.DefaultLanguageCode, jellyfinSettings.Servers.FirstOrDefault()?.ServerHostname ?? string.Empty); - } - + await ProcessMovies(movies, ombiSettings.DefaultLanguageCode); sb.Append(""); sb.Append("
"); sb.Append("
"); } - if ((plexEpisodes.Any() || embyEp.Any() || jellyfinEp.Any()) && !settings.DisableTv) + if (episodes.Any() && !settings.DisableTv) { sb.Append("

New TV



"); sb.Append( @@ -613,21 +467,7 @@ namespace Ombi.Schedule.Jobs.Ombi sb.Append("
"); sb.Append(""); sb.Append(""); - if (plexSettings.Enable) - { - await ProcessPlexTv(plexEpisodes, 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); - } - + await ProcessTv(episodes, ombiSettings.DefaultLanguageCode); sb.Append(""); sb.Append("
"); sb.Append("
"); sb.Append(""); sb.Append(""); - await ProcessAlbums(albums, sb); + await ProcessAlbums(albums); sb.Append(""); sb.Append("
"); sb.Append("