From 29c8b456f413ee6736c843a2891b10aeced8fd9f Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 3 Feb 2017 14:35:41 +0000 Subject: [PATCH 1/6] Removed Plex Request from the notifications --- Ombi.Api/CouchPotatoApi.cs | 12 ++++++------ Ombi.Core.Migration/Migrations/Version2200.cs | 6 +++--- .../Notification/Templates/BasicRequestTemplate.html | 2 +- Ombi.Core/SettingModels/CustomizationSettings.cs | 1 + Ombi.Services/Jobs/Templates/MassEmailTemplate.html | 2 +- .../Jobs/Templates/RecentlyAddedTemplate.html | 2 +- Ombi.UI/Helpers/BaseUrlHelper.cs | 10 +++++++++- Ombi.UI/Views/Customization/Customization.cshtml | 3 ++- 8 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Ombi.Api/CouchPotatoApi.cs b/Ombi.Api/CouchPotatoApi.cs index a6434c30f..8c28faa34 100644 --- a/Ombi.Api/CouchPotatoApi.cs +++ b/Ombi.Api/CouchPotatoApi.cs @@ -100,9 +100,9 @@ namespace Ombi.Api var obj = RetryHandler.Execute(() => Api.Execute(request, url), (exception, timespan) => Log.Error(exception, "Exception when calling GetStatus for CP, Retrying {0}", timespan), new TimeSpan[] { - TimeSpan.FromSeconds (2), - TimeSpan.FromSeconds(5), - TimeSpan.FromSeconds(10)}); + TimeSpan.FromSeconds (1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3)}); return obj; } @@ -140,9 +140,9 @@ namespace Ombi.Api { var obj = RetryHandler.Execute(() => Api.Execute(request, baseUrl), (exception, timespan) => Log.Error(exception, "Exception when calling GetMovies for CP, Retrying {0}", timespan), new[] { - TimeSpan.FromSeconds (5), - TimeSpan.FromSeconds(10), - TimeSpan.FromSeconds(30) + TimeSpan.FromSeconds (1), + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(5) }); return obj; diff --git a/Ombi.Core.Migration/Migrations/Version2200.cs b/Ombi.Core.Migration/Migrations/Version2200.cs index ac9b5d1a7..f2b3b6fd2 100644 --- a/Ombi.Core.Migration/Migrations/Version2200.cs +++ b/Ombi.Core.Migration/Migrations/Version2200.cs @@ -52,8 +52,8 @@ namespace Ombi.Core.Migration.Migrations public void Start(IDbConnection con) { UpdatePlexSettings(); - //UpdateCustomSettings(); Turned off the migration for now until the search has been improved on. - //UpdateSchema(con, Version); + UpdateCustomSettings(); + UpdateSchema(con, Version); } private void UpdatePlexSettings() @@ -68,7 +68,7 @@ namespace Ombi.Core.Migration.Migrations { var settings = Customization.GetSettings(); - settings.NewSearch = true; // Use the new search + settings.EnableIssues = true; Customization.SaveSettings(settings); diff --git a/Ombi.Core/Notification/Templates/BasicRequestTemplate.html b/Ombi.Core/Notification/Templates/BasicRequestTemplate.html index 3e1109517..3e4d5cf56 100644 --- a/Ombi.Core/Notification/Templates/BasicRequestTemplate.html +++ b/Ombi.Core/Notification/Templates/BasicRequestTemplate.html @@ -144,7 +144,7 @@ diff --git a/Ombi.Core/SettingModels/CustomizationSettings.cs b/Ombi.Core/SettingModels/CustomizationSettings.cs index d7aff1e51..98468c9be 100644 --- a/Ombi.Core/SettingModels/CustomizationSettings.cs +++ b/Ombi.Core/SettingModels/CustomizationSettings.cs @@ -54,6 +54,7 @@ namespace Ombi.Core.SettingModels public int DefaultLang { get; set; } public bool NewSearch { get; set; } + public bool EnableIssues { get; set; } } } \ No newline at end of file diff --git a/Ombi.Services/Jobs/Templates/MassEmailTemplate.html b/Ombi.Services/Jobs/Templates/MassEmailTemplate.html index 02214c6af..18a724b93 100644 --- a/Ombi.Services/Jobs/Templates/MassEmailTemplate.html +++ b/Ombi.Services/Jobs/Templates/MassEmailTemplate.html @@ -144,7 +144,7 @@
- +
diff --git a/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html b/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html index f5b208138..932aae99f 100644 --- a/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html +++ b/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html @@ -144,7 +144,7 @@
- +
diff --git a/Ombi.UI/Helpers/BaseUrlHelper.cs b/Ombi.UI/Helpers/BaseUrlHelper.cs index 99c37459e..cb0600ce7 100644 --- a/Ombi.UI/Helpers/BaseUrlHelper.cs +++ b/Ombi.UI/Helpers/BaseUrlHelper.cs @@ -314,6 +314,7 @@ namespace Ombi.UI.Helpers { url = $"/{content}{url}"; } + var returnString = context.Request.Path == url ? $"
  • {title}
  • " : $"
  • {title}
  • "; @@ -328,7 +329,14 @@ namespace Ombi.UI.Helpers { url = $"/{content}{url}"; } - + if (url.Contains("issues")) + { + var custom = GetCustomizationSettings(); + if (!custom.EnableIssues) + { + return helper.Raw(string.Empty); + } + } var returnString = context.Request.Path == url ? $"
  • {title} {extraHtml}
  • " : $"
  • {title} {extraHtml}
  • "; diff --git a/Ombi.UI/Views/Customization/Customization.cshtml b/Ombi.UI/Views/Customization/Customization.cshtml index 583dbabae..a220f950d 100644 --- a/Ombi.UI/Views/Customization/Customization.cshtml +++ b/Ombi.UI/Views/Customization/Customization.cshtml @@ -104,7 +104,8 @@ - @Html.Checkbox(Model.Settings.NewSearch, "NewSearch", "Use New Search") + @*@Html.Checkbox(Model.Settings.NewSearch, "NewSearch", "Use New Search")*@ + @Html.Checkbox(Model.Settings.EnableIssues, "EnableIssues", "Enable Issues")
    From 425522ea06beaf7143c8a9530038aef7356c3870 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 3 Feb 2017 14:45:39 +0000 Subject: [PATCH 2/6] Fixed the mass email, it was only being set to users with the newsletter feature #358 --- Ombi.Services/Interfaces/IRecentlyAdded.cs | 2 +- Ombi.Services/Jobs/RecentlyAdded.cs | 73 +++++++++++++++---- .../Admin/ScheduledJobsRunnerModule.cs | 2 +- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/Ombi.Services/Interfaces/IRecentlyAdded.cs b/Ombi.Services/Interfaces/IRecentlyAdded.cs index c18ca8e27..203d4804b 100644 --- a/Ombi.Services/Interfaces/IRecentlyAdded.cs +++ b/Ombi.Services/Interfaces/IRecentlyAdded.cs @@ -6,6 +6,6 @@ namespace Ombi.Services.Jobs { void Execute(IJobExecutionContext context); void RecentlyAddedAdminTest(); - void Start(); + void StartNewsLetter(); } } \ No newline at end of file diff --git a/Ombi.Services/Jobs/RecentlyAdded.cs b/Ombi.Services/Jobs/RecentlyAdded.cs index 9ee52f231..74474821c 100644 --- a/Ombi.Services/Jobs/RecentlyAdded.cs +++ b/Ombi.Services/Jobs/RecentlyAdded.cs @@ -67,8 +67,6 @@ namespace Ombi.Services.Jobs private IPlexApi Api { get; } private TvMazeApi TvApi = new TvMazeApi(); private readonly TheMovieDbApi _movieApi = new TheMovieDbApi(); - private const int MetadataTypeTv = 4; - private const int MetadataTypeMovie = 1; private ISettingsService PlexSettings { get; } private ISettingsService EmailSettings { get; } private ISettingsService NewsletterSettings { get; } @@ -78,7 +76,7 @@ namespace Ombi.Services.Jobs private static readonly Logger Log = LogManager.GetCurrentClassLogger(); - public void Start() + public void StartNewsLetter() { try { @@ -88,7 +86,7 @@ namespace Ombi.Services.Jobs return; } JobRecord.SetRunning(true, JobNames.RecentlyAddedEmail); - Start(settings); + StartNewsLetter(settings); } catch (Exception e) { @@ -102,35 +100,33 @@ namespace Ombi.Services.Jobs } public void Execute(IJobExecutionContext context) { - Start(); + StartNewsLetter(); } public void RecentlyAddedAdminTest() { Log.Debug("Starting Recently Added Newsletter Test"); var settings = NewsletterSettings.GetSettings(); - Start(settings, true); + StartNewsLetter(settings, true); } + public void MassEmailAdminTest(string html, string subject) { Log.Debug("Starting Mass Email Test"); - var settings = NewsletterSettings.GetSettings(); - var plexSettings = PlexSettings.GetSettings(); var template = new MassEmailTemplate(); var body = template.LoadTemplate(html); - Send(settings, body, plexSettings, true, subject); + SendMassEmail(body, subject, true); } + public void SendMassEmail(string html, string subject) { Log.Debug("Starting Mass Email Test"); - var settings = NewsletterSettings.GetSettings(); - var plexSettings = PlexSettings.GetSettings(); var template = new MassEmailTemplate(); var body = template.LoadTemplate(html); - Send(settings, body, plexSettings, false, subject); + SendMassEmail(body, subject, false); } - private void Start(NewletterSettings newletterSettings, bool testEmail = false) + private void StartNewsLetter(NewletterSettings newletterSettings, bool testEmail = false) { var sb = new StringBuilder(); var plexSettings = PlexSettings.GetSettings(); @@ -222,7 +218,7 @@ namespace Ombi.Services.Jobs string escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray()); Log.Debug(escapedHtml); - Send(newletterSettings, escapedHtml, plexSettings, testEmail); + SendNewsletter(newletterSettings, escapedHtml, plexSettings, testEmail); } private void GenerateMovieHtml(List movies, PlexSettings plexSettings, StringBuilder sb) @@ -457,9 +453,49 @@ namespace Ombi.Services.Jobs sb.Append("
    - +


    "); } - private void Send(NewletterSettings newletterSettings, string html, PlexSettings plexSettings, bool testEmail = false, string subject = "New Content on Plex!") + + private void SendMassEmail(string html, string subject, bool testEmail) { - Log.Debug("Entering Send"); + var settings = EmailSettings.GetSettings(); + + if (!settings.Enabled || string.IsNullOrEmpty(settings.EmailHost)) + { + return; + } + + var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." }; + + var message = new MimeMessage + { + Body = body.ToMessageBody(), + Subject = subject + }; + Log.Debug("Created Plain/HTML MIME body"); + + if (!testEmail) + { + var users = UserHelper.GetUsers(); // Get all users + if (users != null) + { + foreach (var user in users) + { + if (!string.IsNullOrEmpty(user.EmailAddress)) + { + message.Bcc.Add(new MailboxAddress(user.Username, user.EmailAddress)); // BCC everyone + } + } + } + } + message.Bcc.Add(new MailboxAddress(settings.EmailUsername, settings.RecipientEmail)); // Include the admin + + message.From.Add(new MailboxAddress(settings.EmailUsername, settings.EmailSender)); + SendMail(settings, message); + } + + // TODO Emby + private void SendNewsletter(NewletterSettings newletterSettings, string html, bool testEmail = false, string subject = "New Content on Plex!") + { + Log.Debug("Entering SendNewsletter"); var settings = EmailSettings.GetSettings(); if (!settings.Enabled || string.IsNullOrEmpty(settings.EmailHost)) @@ -506,6 +542,11 @@ namespace Ombi.Services.Jobs message.Bcc.Add(new MailboxAddress(settings.EmailUsername, settings.RecipientEmail)); // Include the admin message.From.Add(new MailboxAddress(settings.EmailUsername, settings.EmailSender)); + SendMail(settings, message); + } + + private void SendMail(EmailNotificationSettings settings, MimeMessage message) + { try { using (var client = new SmtpClient()) diff --git a/Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs b/Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs index a08bd056d..2fbe77eb0 100644 --- a/Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs +++ b/Ombi.UI/Modules/Admin/ScheduledJobsRunnerModule.cs @@ -142,7 +142,7 @@ namespace Ombi.UI.Modules.Admin } if (key.Equals(JobNames.RecentlyAddedEmail, StringComparison.CurrentCultureIgnoreCase)) { - RecentlyAdded.Start(); + RecentlyAdded.StartNewsLetter(); } if (key.Equals(JobNames.FaultQueueHandler, StringComparison.CurrentCultureIgnoreCase)) { From 86144f59bb3f4ec8da530f169740e5b49392cda0 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 3 Feb 2017 14:46:11 +0000 Subject: [PATCH 3/6] Fixed build --- Ombi.Services/Jobs/RecentlyAdded.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ombi.Services/Jobs/RecentlyAdded.cs b/Ombi.Services/Jobs/RecentlyAdded.cs index 74474821c..4f9e3b5ca 100644 --- a/Ombi.Services/Jobs/RecentlyAdded.cs +++ b/Ombi.Services/Jobs/RecentlyAdded.cs @@ -218,7 +218,7 @@ namespace Ombi.Services.Jobs string escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray()); Log.Debug(escapedHtml); - SendNewsletter(newletterSettings, escapedHtml, plexSettings, testEmail); + SendNewsletter(newletterSettings, escapedHtml, testEmail); } private void GenerateMovieHtml(List movies, PlexSettings plexSettings, StringBuilder sb) From 8393a31a48655a8c3bc0c384b98741cd16f523fc Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 3 Feb 2017 20:26:28 +0000 Subject: [PATCH 4/6] Reworked the newsletter for Emby! Need to rework it for Plex and use the new way to do it. Fixed collections for Emby #435 --- Ombi.Api.Interfaces/IEmbyApi.cs | 1 + Ombi.Api/EmbyApi.cs | 21 ++ Ombi.Core.Migration/Migrations/Version2200.cs | 8 + Ombi.Services/Jobs/EmbyContentCacher.cs | 80 ++-- Ombi.Services/Jobs/EmbyEpisodeCacher.cs | 51 ++- .../EmbyRecentlyAddedNewsletter.cs | 341 ++++++++++++++++++ .../IEmbyAddedNewsletter.cs | 7 + .../RecentlyAddedNewsletter.cs} | 177 ++++----- Ombi.Services/Ombi.Services.csproj | 4 +- Ombi.Store/Models/Emby/EmbyContent.cs | 1 + Ombi.Store/Models/Emby/EmbyEpisodes.cs | 2 + Ombi.Store/Models/RecenetlyAddedLog.cs | 40 ++ Ombi.Store/Ombi.Store.csproj | 1 + Ombi.Store/SqlTables.sql | 17 +- Ombi.UI/Jobs/Scheduler.cs | 3 +- Ombi.UI/Modules/Admin/AdminModule.cs | 5 + Ombi.UI/NinjectModules/ServicesModule.cs | 6 +- 17 files changed, 631 insertions(+), 134 deletions(-) create mode 100644 Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs create mode 100644 Ombi.Services/Jobs/RecentlyAddedNewsletter/IEmbyAddedNewsletter.cs rename Ombi.Services/Jobs/{RecentlyAdded.cs => RecentlyAddedNewsletter/RecentlyAddedNewsletter.cs} (79%) create mode 100644 Ombi.Store/Models/RecenetlyAddedLog.cs diff --git a/Ombi.Api.Interfaces/IEmbyApi.cs b/Ombi.Api.Interfaces/IEmbyApi.cs index 7a2e4f6c4..ddc85868c 100644 --- a/Ombi.Api.Interfaces/IEmbyApi.cs +++ b/Ombi.Api.Interfaces/IEmbyApi.cs @@ -9,6 +9,7 @@ namespace Ombi.Api.Interfaces EmbyItemContainer GetAllMovies(string apiKey, string userId, Uri baseUri); EmbyItemContainer GetAllShows(string apiKey, string userId, Uri baseUri); EmbyItemContainer GetAllEpisodes(string apiKey, string userId, Uri baseUri); + EmbyItemContainer GetCollection(string mediaId, string apiKey, string userId, Uri baseUrl); List GetUsers(Uri baseUri, string apiKey); EmbyItemContainer ViewLibrary(string apiKey, string userId, Uri baseUri); EmbyInformation GetInformation(string mediaId, EmbyMediaType type, string apiKey, string userId, Uri baseUri); diff --git a/Ombi.Api/EmbyApi.cs b/Ombi.Api/EmbyApi.cs index bbd25dadd..1cfc0bf0a 100644 --- a/Ombi.Api/EmbyApi.cs +++ b/Ombi.Api/EmbyApi.cs @@ -103,6 +103,27 @@ namespace Ombi.Api return GetAll("Episode", apiKey, userId, baseUri); } + public EmbyItemContainer GetCollection(string mediaId, string apiKey, string userId, Uri baseUrl) + { + var request = new RestRequest + { + Resource = "emby/users/{userId}/items?parentId={mediaId}", + Method = Method.GET + }; + + request.AddUrlSegment("userId", userId); + request.AddUrlSegment("mediaId", mediaId); + + AddHeaders(request, apiKey); + + + var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetCollections for Emby, Retrying {0}", timespan), new[] { + TimeSpan.FromSeconds (1), + TimeSpan.FromSeconds(5) + }); + return policy.Execute(() => Api.ExecuteJson>(request, baseUrl)); + } + public EmbyInformation GetInformation(string mediaId, EmbyMediaType type, string apiKey, string userId, Uri baseUri) { var request = new RestRequest diff --git a/Ombi.Core.Migration/Migrations/Version2200.cs b/Ombi.Core.Migration/Migrations/Version2200.cs index f2b3b6fd2..79939c8e3 100644 --- a/Ombi.Core.Migration/Migrations/Version2200.cs +++ b/Ombi.Core.Migration/Migrations/Version2200.cs @@ -30,6 +30,7 @@ using System.Data; using NLog; using Ombi.Core.SettingModels; +using Ombi.Store; namespace Ombi.Core.Migration.Migrations { @@ -53,9 +54,16 @@ namespace Ombi.Core.Migration.Migrations { UpdatePlexSettings(); UpdateCustomSettings(); + AddNewColumns(con); UpdateSchema(con, Version); } + private void AddNewColumns(IDbConnection con) + { + con.AlterTable("EmbyContent", "ADD", "AddedAt", true, "VARCHAR(50)"); + con.AlterTable("EmbyEpisodes", "ADD", "AddedAt", true, "VARCHAR(50)"); + } + private void UpdatePlexSettings() { #if !DEBUG diff --git a/Ombi.Services/Jobs/EmbyContentCacher.cs b/Ombi.Services/Jobs/EmbyContentCacher.cs index 65a47df32..a3eacab65 100644 --- a/Ombi.Services/Jobs/EmbyContentCacher.cs +++ b/Ombi.Services/Jobs/EmbyContentCacher.cs @@ -46,7 +46,7 @@ namespace Ombi.Services.Jobs public class EmbyContentCacher : IJob, IEmbyContentCacher { public EmbyContentCacher(ISettingsService embySettings, IRequestService request, IEmbyApi emby, ICacheProvider cache, - IJobRecord rec, IRepository repo,IRepository content) + IJobRecord rec, IRepository repo, IRepository content) { Emby = embySettings; RequestService = request; @@ -108,35 +108,23 @@ namespace Ombi.Services.Jobs foreach (var m in movies) { - var movieInfo = EmbyApi.GetInformation(m.Id, EmbyMediaType.Movie, embySettings.ApiKey, - embySettings.AdministratorId, embySettings.FullUri).MovieInformation; - - if (string.IsNullOrEmpty(movieInfo.ProviderIds.Imdb)) + if (m.Type.Equals("boxset", StringComparison.CurrentCultureIgnoreCase)) { - Log.Error("Provider Id on movie {0} is null", movieInfo.Name); - continue; - } - - // Check if it exists - var item = EmbyContent.Custom(connection => - { - connection.Open(); - var media = connection.QueryFirstOrDefault("select * from EmbyContent where ProviderId = @ProviderId and type = @type", new { ProviderId = movieInfo.ProviderIds.Imdb, type = 0 }); - connection.Dispose(); - return media; - }); - - if (item == null) - { - // Doesn't exist, insert it - EmbyContent.Insert(new EmbyContent + var info = EmbyApi.GetCollection(m.Id, embySettings.ApiKey, + embySettings.AdministratorId, embySettings.FullUri); + foreach (var item in info.Items) { - ProviderId = movieInfo.ProviderIds.Imdb, - PremierDate = movieInfo.PremiereDate, - Title = movieInfo.Name, - Type = Store.Models.Plex.EmbyMediaType.Movie, - EmbyId = m.Id - }); + var movieInfo = EmbyApi.GetInformation(item.Id, EmbyMediaType.Movie, embySettings.ApiKey, + embySettings.AdministratorId, embySettings.FullUri).MovieInformation; + ProcessMovies(movieInfo); + } + } + else + { + var movieInfo = EmbyApi.GetInformation(m.Id, EmbyMediaType.Movie, embySettings.ApiKey, + embySettings.AdministratorId, embySettings.FullUri).MovieInformation; + + ProcessMovies(movieInfo); } } @@ -170,7 +158,8 @@ namespace Ombi.Services.Jobs PremierDate = tvInfo.PremiereDate, Title = tvInfo.Name, Type = Store.Models.Plex.EmbyMediaType.Series, - EmbyId = t.Id + EmbyId = t.Id, + AddedAt = DateTime.UtcNow }); } } @@ -216,7 +205,7 @@ namespace Ombi.Services.Jobs } } - + private bool ValidateSettings(EmbySettings emby) { @@ -249,5 +238,36 @@ namespace Ombi.Services.Jobs Job.SetRunning(false, JobNames.EmbyCacher); } } + + private void ProcessMovies(EmbyMovieInformation movieInfo) + { + if (string.IsNullOrEmpty(movieInfo.ProviderIds.Imdb)) + { + Log.Error("Provider Id on movie {0} is null", movieInfo.Name); + return; + } + // Check if it exists + var item = EmbyContent.Custom(connection => + { + connection.Open(); + var media = connection.QueryFirstOrDefault("select * from EmbyContent where ProviderId = @ProviderId and type = @type", new { ProviderId = movieInfo.ProviderIds.Imdb, type = 0 }); + connection.Dispose(); + return media; + }); + + if (item == null) + { + // Doesn't exist, insert it + EmbyContent.Insert(new EmbyContent + { + ProviderId = movieInfo.ProviderIds.Imdb, + PremierDate = movieInfo.PremiereDate, + Title = movieInfo.Name, + Type = Store.Models.Plex.EmbyMediaType.Movie, + EmbyId = movieInfo.Id, + AddedAt = DateTime.UtcNow + }); + } + } } } \ No newline at end of file diff --git a/Ombi.Services/Jobs/EmbyEpisodeCacher.cs b/Ombi.Services/Jobs/EmbyEpisodeCacher.cs index 5679a24b9..0135592cc 100644 --- a/Ombi.Services/Jobs/EmbyEpisodeCacher.cs +++ b/Ombi.Services/Jobs/EmbyEpisodeCacher.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Dapper; using NLog; using Ombi.Api.Interfaces; using Ombi.Api.Models.Emby; @@ -65,7 +66,8 @@ namespace Ombi.Services.Jobs private const string TableName = "EmbyEpisodes"; - + // Note, once an episode exists, we store it and it always exists. + // We might want to look at checking if something has been removed from the server in the future. public void CacheEpisodes(EmbySettings settings) { var allEpisodes = EmbyApi.GetAllEpisodes(settings.ApiKey, settings.AdministratorId, settings.FullUri); @@ -74,25 +76,40 @@ namespace Ombi.Services.Jobs { var epInfo = EmbyApi.GetInformation(ep.Id, EmbyMediaType.Episode, settings.ApiKey, settings.AdministratorId, settings.FullUri); - if (epInfo.EpisodeInformation?.ProviderIds?.Tvdb == null) - { - continue; - } - model.Add(new EmbyEpisodes + if (epInfo.EpisodeInformation?.ProviderIds?.Tvdb == null) { - EmbyId = ep.Id, - EpisodeNumber = ep.IndexNumber, - SeasonNumber = ep.ParentIndexNumber, - EpisodeTitle = ep.Name, - ParentId = ep.SeriesId, - ShowTitle = ep.SeriesName, - ProviderId = epInfo.EpisodeInformation.ProviderIds.Tvdb + continue; + } + + // Check it this episode exists + var item = Repo.Custom(connection => + { + connection.Open(); + var media = + connection.QueryFirstOrDefault( + "select * from EmbyEpisodes where ProviderId = @ProviderId", + new {ProviderId = epInfo.EpisodeInformation?.ProviderIds?.Tvdb}); + connection.Dispose(); + return media; }); + + if (item == null) + { + // add it + model.Add(new EmbyEpisodes + { + EmbyId = ep.Id, + EpisodeNumber = ep.IndexNumber, + SeasonNumber = ep.ParentIndexNumber, + EpisodeTitle = ep.Name, + ParentId = ep.SeriesId, + ShowTitle = ep.SeriesName, + ProviderId = epInfo.EpisodeInformation.ProviderIds.Tvdb, + AddedAt = DateTime.UtcNow + }); + } } - - // Delete all of the current items - Repo.DeleteAll(TableName); - + // Insert the new items var result = Repo.BatchInsert(model, TableName, typeof(EmbyEpisodes).GetPropertyNames()); diff --git a/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs b/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs new file mode 100644 index 000000000..cfe752c8a --- /dev/null +++ b/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs @@ -0,0 +1,341 @@ +#region Copyright + +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: RecentlyAddedModel.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ + +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NLog; +using Ombi.Api; +using Ombi.Api.Interfaces; +using Ombi.Api.Models.Emby; +using Ombi.Core; +using Ombi.Core.SettingModels; +using Ombi.Services.Jobs.Templates; +using Ombi.Store.Models; +using Ombi.Store.Models.Emby; +using Ombi.Store.Repository; +using EmbyMediaType = Ombi.Store.Models.Plex.EmbyMediaType; + +namespace Ombi.Services.Jobs.RecentlyAddedNewsletter +{ + public class EmbyAddedNewsletter : HtmlTemplateGenerator, IEmbyAddedNewsletter + { + public EmbyAddedNewsletter(IEmbyApi api, ISettingsService embySettings, + ISettingsService email, + ISettingsService newsletter, IRepository log, + IRepository embyContent, IRepository episodes) + { + Api = api; + EmbySettings = embySettings; + EmailSettings = email; + NewsletterSettings = newsletter; + Content = embyContent; + MovieApi = new TheMovieDbApi(); + TvApi = new TvMazeApi(); + Episodes = episodes; + RecentlyAddedLog = log; + } + + private IEmbyApi Api { get; } + private TheMovieDbApi MovieApi { get; } + private TvMazeApi TvApi { get; } + private ISettingsService EmbySettings { get; } + private ISettingsService EmailSettings { get; } + private ISettingsService NewsletterSettings { get; } + private IRepository Content { get; } + private IRepository Episodes { get; } + private IRepository RecentlyAddedLog { get; } + + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); + + public string GetNewsletterHtml(bool test) + { + try + { + return GetHtml(test); + } + catch (Exception e) + { + Log.Error(e); + return string.Empty; + } + } + + private class EmbyRecentlyAddedModel + { + public EmbyInformation EmbyInformation { get; set; } + public EmbyContent EmbyContent { get; set; } + public List EpisodeInformation { get; set; } + } + + private string GetHtml(bool test) + { + var sb = new StringBuilder(); + var embySettings = EmbySettings.GetSettings(); + + var embyContent = Content.GetAll().ToList(); + + var series = embyContent.Where(x => x.Type == EmbyMediaType.Series).ToList(); + var episodes = Episodes.GetAll().ToList(); + var movie = embyContent.Where(x => x.Type == EmbyMediaType.Movie).ToList(); + + var recentlyAdded = RecentlyAddedLog.GetAll(); + + var filteredMovies = movie.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList(); + var filteredEp = episodes.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList(); + + + var info = new List(); + foreach (var m in filteredMovies) + { + + var i = Api.GetInformation(m.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Movie, + embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri); + info.Add(new EmbyRecentlyAddedModel + { + EmbyInformation = i, + EmbyContent = m + }); + } + GenerateMovieHtml(info, sb); + + info.Clear(); + foreach (var t in series) + { + var i = Api.GetInformation(t.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Series, + embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri); + var ep = filteredEp.Where(x => x.ParentId == t.EmbyId); + + if (ep.Any()) + { + var episodeList = new List(); + foreach (var embyEpisodese in ep) + { + var epInfo = Api.GetInformation(embyEpisodese.EmbyId, Ombi.Api.Models.Emby.EmbyMediaType.Episode, + embySettings.ApiKey, embySettings.AdministratorId, embySettings.FullUri); + episodeList.Add(epInfo.EpisodeInformation); + } + info.Add(new EmbyRecentlyAddedModel + { + EmbyContent = t, + EmbyInformation = i, + EpisodeInformation = episodeList + }); + } + } + GenerateTvHtml(info, sb); + + var template = new RecentlyAddedTemplate(); + var html = template.LoadTemplate(sb.ToString()); + Log.Debug("Loaded the template"); + + if (!test) + { + foreach (var a in filteredMovies) + { + RecentlyAddedLog.Insert(new RecentlyAddedLog + { + ProviderId = a.ProviderId, + AddedAt = DateTime.UtcNow + }); + } + foreach (var a in filteredEp) + { + RecentlyAddedLog.Insert(new RecentlyAddedLog + { + ProviderId = a.ProviderId, + AddedAt = DateTime.UtcNow + }); + } + } + + var escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray()); + Log.Debug(escapedHtml); + return escapedHtml; + } + + private void GenerateMovieHtml(IEnumerable movies, StringBuilder sb) + { + if (!movies.Any()) + { + return; + } + var orderedMovies = movies.OrderByDescending(x => x.EmbyContent.AddedAt).Select(x => x.EmbyInformation.MovieInformation).ToList(); + sb.Append("

    New Movies:



    "); + sb.Append( + ""); + foreach (var movie in orderedMovies) + { + try + { + + var imdbId = movie.ProviderIds.Imdb; + var info = MovieApi.GetMovieInformation(imdbId).Result; + if (info == null) + { + throw new Exception($"Movie with Imdb id {imdbId} returned null from the MovieApi"); + } + AddImageInsideTable(sb, $"https://image.tmdb.org/t/p/w500{info.BackdropPath}"); + + sb.Append(""); + sb.Append( + "
    "); + + Href(sb, $"https://www.imdb.com/title/{info.ImdbId}/"); + Header(sb, 3, $"{info.Title} {info.ReleaseDate?.ToString("yyyy") ?? string.Empty}"); + EndTag(sb, "a"); + + if (info.Genres.Any()) + { + AddParagraph(sb, + $"Genre: {string.Join(", ", info.Genres.Select(x => x.Name.ToString()).ToArray())}"); + } + + AddParagraph(sb, info.Overview); + } + catch (Exception e) + { + Log.Error(e); + Log.Error("Error for movie with IMDB Id = {0}", movie.ProviderIds.Imdb); + } + finally + { + EndLoopHtml(sb); + } + + } + sb.Append("


    "); + } + + private class TvModel + { + public EmbySeriesInformation Series { get; set; } + public List Episodes { get; set; } + } + private void GenerateTvHtml(List tv, StringBuilder sb) + { + if (!tv.Any()) + { + return; + } + var orderedTv = tv.OrderByDescending(x => x.EmbyContent.AddedAt).ToList(); + + // TV + sb.Append("

    New Episodes:



    "); + sb.Append( + ""); + foreach (var t in orderedTv) + { + var seriesItem = t.EmbyInformation.SeriesInformation; + var relatedEpisodes = t.EpisodeInformation; + + + try + { + var info = TvApi.ShowLookupByTheTvDbId(int.Parse(seriesItem.ProviderIds.Tvdb)); + + var banner = info.image?.original; + if (!string.IsNullOrEmpty(banner)) + { + banner = banner.Replace("http", "https"); // Always use the Https banners + } + AddImageInsideTable(sb, banner); + + sb.Append(""); + sb.Append( + "
    "); + + var title = $"{seriesItem.Name} {seriesItem.PremiereDate.Year}"; + + Href(sb, $"https://www.imdb.com/title/{info.externals.imdb}/"); + Header(sb, 3, title); + EndTag(sb, "a"); + + var results = relatedEpisodes.GroupBy(p => p.ParentIndexNumber, + (key, g) => new + { + ParentIndexNumber = key, + IndexNumber = g.ToList() + } + ); + // Group the episodes + foreach (var embyEpisodeInformation in results.OrderBy(x => x.ParentIndexNumber)) + { + var epSb = new StringBuilder(); + for (var i = 0; i < embyEpisodeInformation.IndexNumber.Count; i++) + { + var ep = embyEpisodeInformation.IndexNumber[i]; + if (i < embyEpisodeInformation.IndexNumber.Count) + { + epSb.Append($"{ep.IndexNumber},"); + } + else + { + epSb.Append(ep); + } + } + AddParagraph(sb, $"Season: {embyEpisodeInformation.ParentIndexNumber}, Episode: {epSb}"); + } + + if (info.genres.Any()) + { + AddParagraph(sb, $"Genre: {string.Join(", ", info.genres.Select(x => x.ToString()).ToArray())}"); + } + + AddParagraph(sb, string.IsNullOrEmpty(seriesItem.Overview) ? info.summary : seriesItem.Overview); + } + catch (Exception e) + { + Log.Error(e); + } + finally + { + EndLoopHtml(sb); + } + } + sb.Append("


    "); + } + + + + + private void EndLoopHtml(StringBuilder sb) + { + //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 + sb.Append("
    "); + sb.Append("
    "); + sb.Append("
    "); + sb.Append(""); + sb.Append(""); + } + + } +} \ No newline at end of file diff --git a/Ombi.Services/Jobs/RecentlyAddedNewsletter/IEmbyAddedNewsletter.cs b/Ombi.Services/Jobs/RecentlyAddedNewsletter/IEmbyAddedNewsletter.cs new file mode 100644 index 000000000..bef09ce6e --- /dev/null +++ b/Ombi.Services/Jobs/RecentlyAddedNewsletter/IEmbyAddedNewsletter.cs @@ -0,0 +1,7 @@ +namespace Ombi.Services.Jobs.RecentlyAddedNewsletter +{ + public interface IEmbyAddedNewsletter + { + string GetNewsletterHtml(bool test); + } +} \ No newline at end of file diff --git a/Ombi.Services/Jobs/RecentlyAdded.cs b/Ombi.Services/Jobs/RecentlyAddedNewsletter/RecentlyAddedNewsletter.cs similarity index 79% rename from Ombi.Services/Jobs/RecentlyAdded.cs rename to Ombi.Services/Jobs/RecentlyAddedNewsletter/RecentlyAddedNewsletter.cs index 4f9e3b5ca..0183058d0 100644 --- a/Ombi.Services/Jobs/RecentlyAdded.cs +++ b/Ombi.Services/Jobs/RecentlyAddedNewsletter/RecentlyAddedNewsletter.cs @@ -46,14 +46,15 @@ using Ombi.Services.Interfaces; using Ombi.Services.Jobs.Templates; using Quartz; -namespace Ombi.Services.Jobs +namespace Ombi.Services.Jobs.RecentlyAddedNewsletter { - public class RecentlyAdded : HtmlTemplateGenerator, IJob, IRecentlyAdded, IMassEmail + public class RecentlyAddedNewsletter : HtmlTemplateGenerator, IJob, IRecentlyAdded, IMassEmail { - public RecentlyAdded(IPlexApi api, ISettingsService plexSettings, + public RecentlyAddedNewsletter(IPlexApi api, ISettingsService plexSettings, ISettingsService email, IJobRecord rec, ISettingsService newsletter, - IPlexReadOnlyDatabase db, IUserHelper userHelper) + IPlexReadOnlyDatabase db, IUserHelper userHelper, IEmbyAddedNewsletter embyNews, + ISettingsService embyS) { JobRecord = rec; Api = api; @@ -62,17 +63,21 @@ namespace Ombi.Services.Jobs NewsletterSettings = newsletter; PlexDb = db; UserHelper = userHelper; + EmbyNewsletter = embyNews; + EmbySettings = embyS; } private IPlexApi Api { get; } private TvMazeApi TvApi = new TvMazeApi(); private readonly TheMovieDbApi _movieApi = new TheMovieDbApi(); private ISettingsService PlexSettings { get; } + private ISettingsService EmbySettings { get; } private ISettingsService EmailSettings { get; } private ISettingsService NewsletterSettings { get; } private IJobRecord JobRecord { get; } private IPlexReadOnlyDatabase PlexDb { get; } private IUserHelper UserHelper { get; } + private IEmbyAddedNewsletter EmbyNewsletter { get; } private static readonly Logger Log = LogManager.GetCurrentClassLogger(); @@ -128,97 +133,107 @@ namespace Ombi.Services.Jobs private void StartNewsLetter(NewletterSettings newletterSettings, bool testEmail = false) { - var sb = new StringBuilder(); - var plexSettings = PlexSettings.GetSettings(); - Log.Debug("Got Plex Settings"); - - var libs = Api.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri); - Log.Debug("Getting Plex Library Sections"); - - var tvSections = libs.Directories.Where(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)); // We could have more than 1 lib - Log.Debug("Filtered sections for TV"); - var movieSection = libs.Directories.Where(x => x.type.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase)); // We could have more than 1 lib - Log.Debug("Filtered sections for Movies"); - - var plexVersion = Api.GetStatus(plexSettings.PlexAuthToken, plexSettings.FullUri).Version; - - var html = string.Empty; - if (plexVersion.StartsWith("1.3")) + var embySettings = EmbySettings.GetSettings(); + if (embySettings.Enable) { - var tvMetadata = new List(); - var movieMetadata = new List(); - foreach (var tvSection in tvSections) - { - var item = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, - tvSection?.Key); - if (item?.MediaContainer?.Metadata != null) - { - tvMetadata.AddRange(item?.MediaContainer?.Metadata); - } - } - Log.Debug("Got RecentlyAdded TV Shows"); - foreach (var movie in movieSection) - { - var recentlyAddedMovies = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, movie?.Key); - if (recentlyAddedMovies?.MediaContainer?.Metadata != null) - { - movieMetadata.AddRange(recentlyAddedMovies?.MediaContainer?.Metadata); - } - } - Log.Debug("Got RecentlyAdded Movies"); + var html = EmbyNewsletter.GetNewsletterHtml(testEmail); - Log.Debug("Started Generating Movie HTML"); - GenerateMovieHtml(movieMetadata, plexSettings, sb); - Log.Debug("Finished Generating Movie HTML"); - Log.Debug("Started Generating TV HTML"); - GenerateTvHtml(tvMetadata, plexSettings, sb); - Log.Debug("Finished Generating TV HTML"); - - var template = new RecentlyAddedTemplate(); - html = template.LoadTemplate(sb.ToString()); - Log.Debug("Loaded the template"); + var escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray()); + Log.Debug(escapedHtml); + SendNewsletter(newletterSettings, escapedHtml, testEmail); } else { - // Old API - var tvChild = new List(); - var movieChild = new List(); - foreach (var tvSection in tvSections) + var sb = new StringBuilder(); + var plexSettings = PlexSettings.GetSettings(); + Log.Debug("Got Plex Settings"); + + var libs = Api.GetLibrarySections(plexSettings.PlexAuthToken, plexSettings.FullUri); + Log.Debug("Getting Plex Library Sections"); + + var tvSections = libs.Directories.Where(x => x.type.Equals(PlexMediaType.Show.ToString(), StringComparison.CurrentCultureIgnoreCase)); // We could have more than 1 lib + Log.Debug("Filtered sections for TV"); + var movieSection = libs.Directories.Where(x => x.type.Equals(PlexMediaType.Movie.ToString(), StringComparison.CurrentCultureIgnoreCase)); // We could have more than 1 lib + Log.Debug("Filtered sections for Movies"); + + var plexVersion = Api.GetStatus(plexSettings.PlexAuthToken, plexSettings.FullUri).Version; + + var html = string.Empty; + if (plexVersion.StartsWith("1.3")) { - var recentlyAddedTv = Api.RecentlyAddedOld(plexSettings.PlexAuthToken, plexSettings.FullUri, tvSection?.Key); - if (recentlyAddedTv?._children != null) + var tvMetadata = new List(); + var movieMetadata = new List(); + foreach (var tvSection in tvSections) { - tvChild.AddRange(recentlyAddedTv?._children); + var item = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, + tvSection?.Key); + if (item?.MediaContainer?.Metadata != null) + { + tvMetadata.AddRange(item?.MediaContainer?.Metadata); + } } - } + Log.Debug("Got RecentlyAdded TV Shows"); + foreach (var movie in movieSection) + { + var recentlyAddedMovies = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, movie?.Key); + if (recentlyAddedMovies?.MediaContainer?.Metadata != null) + { + movieMetadata.AddRange(recentlyAddedMovies?.MediaContainer?.Metadata); + } + } + Log.Debug("Got RecentlyAdded Movies"); - Log.Debug("Got RecentlyAdded TV Shows"); - foreach (var movie in movieSection) + Log.Debug("Started Generating Movie HTML"); + GenerateMovieHtml(movieMetadata, plexSettings, sb); + Log.Debug("Finished Generating Movie HTML"); + Log.Debug("Started Generating TV HTML"); + GenerateTvHtml(tvMetadata, plexSettings, sb); + Log.Debug("Finished Generating TV HTML"); + + var template = new RecentlyAddedTemplate(); + html = template.LoadTemplate(sb.ToString()); + Log.Debug("Loaded the template"); + } + else { - var recentlyAddedMovies = Api.RecentlyAddedOld(plexSettings.PlexAuthToken, plexSettings.FullUri, movie?.Key); - if (recentlyAddedMovies?._children != null) + // Old API + var tvChild = new List(); + var movieChild = new List(); + foreach (var tvSection in tvSections) { - tvChild.AddRange(recentlyAddedMovies?._children); + var recentlyAddedTv = Api.RecentlyAddedOld(plexSettings.PlexAuthToken, plexSettings.FullUri, tvSection?.Key); + if (recentlyAddedTv?._children != null) + { + tvChild.AddRange(recentlyAddedTv?._children); + } } + + Log.Debug("Got RecentlyAdded TV Shows"); + foreach (var movie in movieSection) + { + var recentlyAddedMovies = Api.RecentlyAddedOld(plexSettings.PlexAuthToken, plexSettings.FullUri, movie?.Key); + if (recentlyAddedMovies?._children != null) + { + tvChild.AddRange(recentlyAddedMovies?._children); + } + } + Log.Debug("Got RecentlyAdded Movies"); + + Log.Debug("Started Generating Movie HTML"); + GenerateMovieHtml(movieChild, plexSettings, sb); + Log.Debug("Finished Generating Movie HTML"); + Log.Debug("Started Generating TV HTML"); + GenerateTvHtml(tvChild, plexSettings, sb); + Log.Debug("Finished Generating TV HTML"); + + var template = new RecentlyAddedTemplate(); + html = template.LoadTemplate(sb.ToString()); + Log.Debug("Loaded the template"); } - Log.Debug("Got RecentlyAdded Movies"); - - Log.Debug("Started Generating Movie HTML"); - GenerateMovieHtml(movieChild, plexSettings, sb); - Log.Debug("Finished Generating Movie HTML"); - Log.Debug("Started Generating TV HTML"); - GenerateTvHtml(tvChild, plexSettings, sb); - Log.Debug("Finished Generating TV HTML"); - - var template = new RecentlyAddedTemplate(); - html = template.LoadTemplate(sb.ToString()); - Log.Debug("Loaded the template"); + string escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray()); + Log.Debug(escapedHtml); + SendNewsletter(newletterSettings, escapedHtml, testEmail); } - - - string escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray()); - Log.Debug(escapedHtml); - SendNewsletter(newletterSettings, escapedHtml, testEmail); } private void GenerateMovieHtml(List movies, PlexSettings plexSettings, StringBuilder sb) diff --git a/Ombi.Services/Ombi.Services.csproj b/Ombi.Services/Ombi.Services.csproj index a37279f7d..17093e031 100644 --- a/Ombi.Services/Ombi.Services.csproj +++ b/Ombi.Services/Ombi.Services.csproj @@ -108,6 +108,8 @@ + + @@ -117,7 +119,7 @@ - + diff --git a/Ombi.Store/Models/Emby/EmbyContent.cs b/Ombi.Store/Models/Emby/EmbyContent.cs index 799487755..07f211cc3 100644 --- a/Ombi.Store/Models/Emby/EmbyContent.cs +++ b/Ombi.Store/Models/Emby/EmbyContent.cs @@ -39,5 +39,6 @@ namespace Ombi.Store.Models.Emby public DateTime PremierDate { get; set; } public string ProviderId { get; set; } public EmbyMediaType Type { get; set; } + public DateTime AddedAt { get; set; } } } \ No newline at end of file diff --git a/Ombi.Store/Models/Emby/EmbyEpisodes.cs b/Ombi.Store/Models/Emby/EmbyEpisodes.cs index a1b900455..24d41f052 100644 --- a/Ombi.Store/Models/Emby/EmbyEpisodes.cs +++ b/Ombi.Store/Models/Emby/EmbyEpisodes.cs @@ -25,6 +25,7 @@ // ************************************************************************/ #endregion +using System; using Dapper.Contrib.Extensions; namespace Ombi.Store.Models.Emby @@ -39,5 +40,6 @@ namespace Ombi.Store.Models.Emby public int SeasonNumber { get; set; } public string ParentId { get; set; } public string ProviderId { get; set; } + public DateTime AddedAt { get; set; } } } \ No newline at end of file diff --git a/Ombi.Store/Models/RecenetlyAddedLog.cs b/Ombi.Store/Models/RecenetlyAddedLog.cs new file mode 100644 index 000000000..4f7a75aba --- /dev/null +++ b/Ombi.Store/Models/RecenetlyAddedLog.cs @@ -0,0 +1,40 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: LogEntity.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion + +using System; +using Dapper.Contrib.Extensions; +using Newtonsoft.Json; + +namespace Ombi.Store.Models +{ + [Table("RecentlyAddedLog")] + public class RecentlyAddedLog : Entity + { + public string ProviderId { get; set; } + public DateTime AddedAt { get; set; } + } +} diff --git a/Ombi.Store/Ombi.Store.csproj b/Ombi.Store/Ombi.Store.csproj index 6bfaa021b..06a0b59fc 100644 --- a/Ombi.Store/Ombi.Store.csproj +++ b/Ombi.Store/Ombi.Store.csproj @@ -68,6 +68,7 @@ + diff --git a/Ombi.Store/SqlTables.sql b/Ombi.Store/SqlTables.sql index f548381a8..cdf5a2f80 100644 --- a/Ombi.Store/SqlTables.sql +++ b/Ombi.Store/SqlTables.sql @@ -187,7 +187,8 @@ CREATE TABLE IF NOT EXISTS EmbyEpisodes SeasonNumber INTEGER NOT NULL, EpisodeNumber INTEGER NOT NULL, ParentId VARCHAR(100) NOT NULL, - ProviderId VARCHAR(100) NOT NULL + ProviderId VARCHAR(100) NOT NULL, + AddedAt VARCHAR(100) NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS EmbyEpisodes_Id ON EmbyEpisodes (Id); @@ -198,9 +199,21 @@ CREATE TABLE IF NOT EXISTS EmbyContent PremierDate VARCHAR(100) NOT NULL, EmbyId VARCHAR(100) NOT NULL, ProviderId VARCHAR(100) NOT NULL, - Type INTEGER NOT NULL + Type INTEGER NOT NULL, + AddedAt VARCHAR(100) NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS EmbyEpisodes_Id ON EmbyEpisodes (Id); +CREATE TABLE IF NOT EXISTS RecentlyAddedLog +( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + ProviderId VARCHAR(100) NOT NULL, + AddedAt VARCHAR(100) NOT NULL + +); +CREATE UNIQUE INDEX IF NOT EXISTS RecentlyAddedLog_Id ON RecentlyAddedLog (Id); + +CREATE INDEX IF NOT EXISTS RecentlyAddedLog_ProviderId ON RecentlyAddedLog (ProviderId); + COMMIT; \ No newline at end of file diff --git a/Ombi.UI/Jobs/Scheduler.cs b/Ombi.UI/Jobs/Scheduler.cs index 8f43a02b3..d824701c9 100644 --- a/Ombi.UI/Jobs/Scheduler.cs +++ b/Ombi.UI/Jobs/Scheduler.cs @@ -35,6 +35,7 @@ using Ombi.Core; using Ombi.Core.SettingModels; using Ombi.Services.Interfaces; using Ombi.Services.Jobs; +using Ombi.Services.Jobs.RecentlyAddedNewsletter; using Ombi.UI.Helpers; using Quartz; using Quartz.Impl; @@ -70,7 +71,7 @@ namespace Ombi.UI.Jobs JobBuilder.Create().WithIdentity("StoreBackup", "Database").Build(), JobBuilder.Create().WithIdentity("StoreCleanup", "Database").Build(), JobBuilder.Create().WithIdentity("UserRequestLimiter", "Request").Build(), - JobBuilder.Create().WithIdentity("RecentlyAddedModel", "Email").Build(), + JobBuilder.Create().WithIdentity("RecentlyAddedModel", "Email").Build(), JobBuilder.Create().WithIdentity("FaultQueueHandler", "Fault").Build(), JobBuilder.Create().WithIdentity("RadarrCacher", "Cache").Build(), diff --git a/Ombi.UI/Modules/Admin/AdminModule.cs b/Ombi.UI/Modules/Admin/AdminModule.cs index 388a66ef0..8faab45d6 100644 --- a/Ombi.UI/Modules/Admin/AdminModule.cs +++ b/Ombi.UI/Modules/Admin/AdminModule.cs @@ -42,6 +42,7 @@ using Nancy.Validation; using NLog; using Ombi.Api; using Ombi.Api.Interfaces; +using Ombi.Api.Models.Movie; using Ombi.Core; using Ombi.Core.Models; using Ombi.Core.SettingModels; @@ -823,6 +824,10 @@ namespace Ombi.UI.Modules.Admin { return Response.AsJson(valid.SendJsonError()); } + if (!settings.Enabled) + { + return Response.AsJson(new CouchPotatoProfiles{list = new List()}); + } var profiles = CpApi.GetProfiles(settings.FullUri, settings.ApiKey); // set the cache diff --git a/Ombi.UI/NinjectModules/ServicesModule.cs b/Ombi.UI/NinjectModules/ServicesModule.cs index 95fbe4ba5..210cdfd3e 100644 --- a/Ombi.UI/NinjectModules/ServicesModule.cs +++ b/Ombi.UI/NinjectModules/ServicesModule.cs @@ -32,6 +32,7 @@ using Ombi.Helpers.Analytics; using Ombi.Services.Interfaces; using Ombi.Services.Jobs; using Ombi.Services.Jobs.Interfaces; +using Ombi.Services.Jobs.RecentlyAddedNewsletter; using Ombi.UI.Jobs; using Quartz; using Quartz.Impl; @@ -48,8 +49,8 @@ namespace Ombi.UI.NinjectModules Bind().To(); Bind().To(); Bind().To(); - Bind().To(); - Bind().To(); + Bind().To(); + Bind().To(); Bind().To(); Bind().To(); Bind().To(); @@ -65,6 +66,7 @@ namespace Ombi.UI.NinjectModules Bind().To(); Bind().To(); Bind().To(); + Bind().To(); Bind().To(); From 74066d0351580283b323d42f4efb64432f26218f Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 3 Feb 2017 20:34:05 +0000 Subject: [PATCH 5/6] First run of the newsletter set it to a test --- .../RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs b/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs index cfe752c8a..07963008d 100644 --- a/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs +++ b/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs @@ -106,7 +106,9 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter var episodes = Episodes.GetAll().ToList(); var movie = embyContent.Where(x => x.Type == EmbyMediaType.Movie).ToList(); - var recentlyAdded = RecentlyAddedLog.GetAll(); + var recentlyAdded = RecentlyAddedLog.GetAll().ToList(); + + var firstRun = !recentlyAdded.Any(); var filteredMovies = movie.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList(); var filteredEp = episodes.Where(m => recentlyAdded.All(x => x.ProviderId != m.ProviderId)).ToList(); @@ -156,7 +158,7 @@ namespace Ombi.Services.Jobs.RecentlyAddedNewsletter var html = template.LoadTemplate(sb.ToString()); Log.Debug("Loaded the template"); - if (!test) + if (!test || firstRun) { foreach (var a in filteredMovies) { From 2dfcef980e71338b265ce315a103bb34814c7796 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 3 Feb 2017 20:45:55 +0000 Subject: [PATCH 6/6] Removed plex from the scheduled jobs ui --- Ombi.UI/Jobs/Scheduler.cs | 4 ++-- Ombi.UI/Modules/Admin/AdminModule.cs | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Ombi.UI/Jobs/Scheduler.cs b/Ombi.UI/Jobs/Scheduler.cs index d824701c9..b0f5266cd 100644 --- a/Ombi.UI/Jobs/Scheduler.cs +++ b/Ombi.UI/Jobs/Scheduler.cs @@ -305,8 +305,8 @@ namespace Ombi.UI.Jobs var embyEpisode = TriggerBuilder.Create() .WithIdentity("EmbyEpisodeCacher", "Emby") - .StartNow() - //.StartAt(DateBuilder.FutureDate(10, IntervalUnit.Minute)) + //.StartNow() + .StartAt(DateBuilder.FutureDate(10, IntervalUnit.Minute)) .WithSimpleSchedule(x => x.WithIntervalInHours(s.EmbyEpisodeCacher).RepeatForever()) .Build(); diff --git a/Ombi.UI/Modules/Admin/AdminModule.cs b/Ombi.UI/Modules/Admin/AdminModule.cs index 8faab45d6..c9bce2faf 100644 --- a/Ombi.UI/Modules/Admin/AdminModule.cs +++ b/Ombi.UI/Modules/Admin/AdminModule.cs @@ -1146,6 +1146,8 @@ namespace Ombi.UI.Modules.Admin var emby = await EmbySettings.GetSettingsAsync(); var plex = await PlexService.GetSettingsAsync(); + + var dict = new Dictionary(); @@ -1158,7 +1160,24 @@ namespace Ombi.UI.Modules.Admin } else { - dict.Add(j.Name,j.LastRun); + if (j.Name.Contains("Plex")) + { + if (plex.Enable) + { + dict.Add(j.Name, j.LastRun); + } + } + else if (j.Name.Contains("Emby")) + { + if (emby.Enable) + { + dict.Add(j.Name, j.LastRun); + } + } + else + { + dict.Add(j.Name, j.LastRun); + } } }