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.Models/Emby/EmbyEpisodeInformation.cs b/Ombi.Api.Models/Emby/EmbyEpisodeInformation.cs index be173faf9..1cdb2985c 100644 --- a/Ombi.Api.Models/Emby/EmbyEpisodeInformation.cs +++ b/Ombi.Api.Models/Emby/EmbyEpisodeInformation.cs @@ -49,7 +49,7 @@ namespace Ombi.Api.Models.Emby public object[] Taglines { get; set; } public object[] Genres { get; set; } public string[] SeriesGenres { get; set; } - public int CommunityRating { get; set; } + public float CommunityRating { get; set; } public int VoteCount { get; set; } public long RunTimeTicks { get; set; } public string PlayAccess { get; set; } 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.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 ac9b5d1a7..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 { @@ -52,8 +53,15 @@ 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(); + 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() @@ -68,7 +76,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/CacheKeys.cs b/Ombi.Core/CacheKeys.cs index 39ed7a71b..32466e897 100644 --- a/Ombi.Core/CacheKeys.cs +++ b/Ombi.Core/CacheKeys.cs @@ -45,6 +45,8 @@ namespace Ombi.Core public const string CouchPotatoQualityProfiles = nameof(CouchPotatoQualityProfiles); public const string CouchPotatoQueued = nameof(CouchPotatoQueued); public const string WatcherQueued = nameof(WatcherQueued); + public const string GetCustomizationSettings = nameof(GetCustomizationSettings); + public const string GetEmbySettings = nameof(GetEmbySettings); public const string GetPlexRequestSettings = nameof(GetPlexRequestSettings); public const string LastestProductVersion = nameof(LastestProductVersion); public const string SonarrRootFolders = nameof(SonarrRootFolders); 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/Ombi.Core.csproj b/Ombi.Core/Ombi.Core.csproj index 9866e6fb0..f6562c2fc 100644 --- a/Ombi.Core/Ombi.Core.csproj +++ b/Ombi.Core/Ombi.Core.csproj @@ -124,6 +124,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.Core/SettingModels/MassEmailSettings.cs b/Ombi.Core/SettingModels/MassEmailSettings.cs new file mode 100644 index 000000000..0be28a92d --- /dev/null +++ b/Ombi.Core/SettingModels/MassEmailSettings.cs @@ -0,0 +1,35 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: EmailNotificationSettings.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +namespace Ombi.Core.SettingModels +{ + public sealed class MassEmailSettings : NotificationSettings + { + public string Users { get; set; } + public string Subject { get; set; } + public string Body { get; set; } + } +} \ No newline at end of file diff --git a/Ombi.Services/Interfaces/IMassEmail.cs b/Ombi.Services/Interfaces/IMassEmail.cs new file mode 100644 index 000000000..9751cc870 --- /dev/null +++ b/Ombi.Services/Interfaces/IMassEmail.cs @@ -0,0 +1,12 @@ +using Quartz; + +namespace Ombi.Services.Jobs +{ + public interface IMassEmail + { + void Execute(IJobExecutionContext context); + void MassEmailAdminTest(string html, string subject); + void SendMassEmail(string html, string subject); + + } +} \ No newline at end of file diff --git a/Ombi.Services/Interfaces/IRecentlyAdded.cs b/Ombi.Services/Interfaces/IRecentlyAdded.cs index 09a7220f5..203d4804b 100644 --- a/Ombi.Services/Interfaces/IRecentlyAdded.cs +++ b/Ombi.Services/Interfaces/IRecentlyAdded.cs @@ -5,7 +5,7 @@ namespace Ombi.Services.Jobs public interface IRecentlyAdded { void Execute(IJobExecutionContext context); - void Test(); - void Start(); + void RecentlyAddedAdminTest(); + void StartNewsLetter(); } } \ No newline at end of file diff --git a/Ombi.Services/Jobs/EmbyAvailabilityChecker.cs b/Ombi.Services/Jobs/EmbyAvailabilityChecker.cs index a86a7469d..166ed987a 100644 --- a/Ombi.Services/Jobs/EmbyAvailabilityChecker.cs +++ b/Ombi.Services/Jobs/EmbyAvailabilityChecker.cs @@ -286,7 +286,9 @@ namespace Ombi.Services.Jobs var ep = await EpisodeRepo.CustomAsync(async connection => { connection.Open(); - var result = await connection.QueryAsync("select * from EmbyEpisodes where ProviderId = @ProviderId", new { ProviderId = theTvDbId }); + var result = await connection.QueryAsync(@"select ee.* from EmbyEpisodes ee inner join EmbyContent ec + on ee.ParentId = ec.EmbyId + where ec.ProviderId = @ProviderId", new { ProviderId = theTvDbId }); return result; }); 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; + var info = EmbyApi.GetCollection(m.Id, embySettings.ApiKey, + embySettings.AdministratorId, embySettings.FullUri); + foreach (var item in info.Items) + { + var movieInfo = EmbyApi.GetInformation(item.Id, EmbyMediaType.Movie, embySettings.ApiKey, + embySettings.AdministratorId, embySettings.FullUri).MovieInformation; + ProcessMovies(movieInfo); + } } - - // Check if it exists - var item = EmbyContent.Custom(connection => + else { - 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; - }); + var movieInfo = EmbyApi.GetInformation(m.Id, EmbyMediaType.Movie, embySettings.ApiKey, + embySettings.AdministratorId, embySettings.FullUri).MovieInformation; - 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 = m.Id - }); + 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 945908149..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,21 +76,40 @@ namespace Ombi.Services.Jobs { var epInfo = EmbyApi.GetInformation(ep.Id, EmbyMediaType.Episode, settings.ApiKey, settings.AdministratorId, settings.FullUri); - 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.Tmdb - }); - } + continue; + } - // Delete all of the current items - Repo.DeleteAll(TableName); + // 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 + }); + } + } + // Insert the new items var result = Repo.BatchInsert(model, TableName, typeof(EmbyEpisodes).GetPropertyNames()); @@ -108,15 +129,6 @@ namespace Ombi.Services.Jobs return; } - var jobs = Job.GetJobs(); - var job = jobs.FirstOrDefault(x => x.Name.Equals(JobNames.EmbyEpisodeCacher, StringComparison.CurrentCultureIgnoreCase)); - if (job != null) - { - if (job.LastRun > DateTime.Now.AddHours(-11)) // If it's been run in the last 11 hours - { - return; - } - } Job.SetRunning(true, JobNames.EmbyEpisodeCacher); CacheEpisodes(s); } @@ -141,15 +153,6 @@ namespace Ombi.Services.Jobs return; } - var jobs = Job.GetJobs(); - var job = jobs.FirstOrDefault(x => x.Name.Equals(JobNames.EmbyEpisodeCacher, StringComparison.CurrentCultureIgnoreCase)); - if (job != null) - { - if (job.LastRun > DateTime.Now.AddHours(-11)) // If it's been run in the last 11 hours - { - return; - } - } Job.SetRunning(true, JobNames.EmbyEpisodeCacher); CacheEpisodes(s); } diff --git a/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs b/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs new file mode 100644 index 000000000..07963008d --- /dev/null +++ b/Ombi.Services/Jobs/RecentlyAddedNewsletter/EmbyRecentlyAddedNewsletter.cs @@ -0,0 +1,343 @@ +#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().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(); + + + 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 || firstRun) + { + 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 68% rename from Ombi.Services/Jobs/RecentlyAdded.cs rename to Ombi.Services/Jobs/RecentlyAddedNewsletter/RecentlyAddedNewsletter.cs index 563dd35a5..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 + 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,23 +63,25 @@ 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 const int MetadataTypeTv = 4; - private const int MetadataTypeMovie = 1; 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(); - public void Start() + public void StartNewsLetter() { try { @@ -88,7 +91,7 @@ namespace Ombi.Services.Jobs return; } JobRecord.SetRunning(true, JobNames.RecentlyAddedEmail); - Start(settings); + StartNewsLetter(settings); } catch (Exception e) { @@ -102,109 +105,135 @@ namespace Ombi.Services.Jobs } public void Execute(IJobExecutionContext context) { - Start(); + StartNewsLetter(); } - public void Test() + public void RecentlyAddedAdminTest() { - Log.Debug("Starting Test Newsletter"); + Log.Debug("Starting Recently Added Newsletter Test"); var settings = NewsletterSettings.GetSettings(); - Start(settings, true); + StartNewsLetter(settings, true); } - private void Start(NewletterSettings newletterSettings, bool testEmail = false) + public void MassEmailAdminTest(string html, string subject) { - 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"); + Log.Debug("Starting Mass Email Test"); + var template = new MassEmailTemplate(); + var body = template.LoadTemplate(html); + SendMassEmail(body, subject, true); + } - 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"); + public void SendMassEmail(string html, string subject) + { + Log.Debug("Starting Mass Email Test"); + var template = new MassEmailTemplate(); + var body = template.LoadTemplate(html); + SendMassEmail(body, subject, false); + } - var plexVersion = Api.GetStatus(plexSettings.PlexAuthToken, plexSettings.FullUri).Version; + private void StartNewsLetter(NewletterSettings newletterSettings, bool testEmail = false) + { + var embySettings = EmbySettings.GetSettings(); + if (embySettings.Enable) + { + var html = EmbyNewsletter.GetNewsletterHtml(testEmail); - var html = string.Empty; - if (plexVersion.StartsWith("1.3")) + var escapedHtml = new string(html.Where(c => !char.IsControl(c)).ToArray()); + Log.Debug(escapedHtml); + SendNewsletter(newletterSettings, escapedHtml, testEmail); + } + else { - var tvMetadata = new List(); - var movieMetadata = 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 item = Api.RecentlyAdded(plexSettings.PlexAuthToken, plexSettings.FullUri, - tvSection?.Key); - if (item?.MediaContainer?.Metadata != null) + var tvMetadata = new List(); + var movieMetadata = new List(); + foreach (var tvSection in tvSections) { - tvMetadata.AddRange(item?.MediaContainer?.Metadata); + 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) + Log.Debug("Got RecentlyAdded TV Shows"); + foreach (var movie in movieSection) { - movieMetadata.AddRange(recentlyAddedMovies?.MediaContainer?.Metadata); + 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("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"); } - Log.Debug("Got RecentlyAdded Movies"); - - 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 - { - // Old API - var tvChild = new List(); - var movieChild = new List(); - foreach (var tvSection in tvSections) + else { - var recentlyAddedTv = Api.RecentlyAddedOld(plexSettings.PlexAuthToken, plexSettings.FullUri, tvSection?.Key); - if (recentlyAddedTv?._children != null) + // Old API + var tvChild = new List(); + var movieChild = new List(); + foreach (var tvSection in tvSections) { - tvChild.AddRange(recentlyAddedTv?._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) + Log.Debug("Got RecentlyAdded TV Shows"); + foreach (var movie in movieSection) { - tvChild.AddRange(recentlyAddedMovies?._children); + 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); - Send(newletterSettings, escapedHtml, plexSettings, testEmail); } private void GenerateMovieHtml(List movies, PlexSettings plexSettings, StringBuilder sb) @@ -439,9 +468,49 @@ namespace Ombi.Services.Jobs sb.Append("

"); } - private void Send(NewletterSettings newletterSettings, string html, PlexSettings plexSettings, bool testEmail = false) + + private void SendMassEmail(string html, string subject, bool testEmail) + { + 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 Send"); + Log.Debug("Entering SendNewsletter"); var settings = EmailSettings.GetSettings(); if (!settings.Enabled || string.IsNullOrEmpty(settings.EmailHost)) @@ -454,7 +523,7 @@ namespace Ombi.Services.Jobs var message = new MimeMessage { Body = body.ToMessageBody(), - Subject = "New Content on Plex!", + Subject = subject }; Log.Debug("Created Plain/HTML MIME body"); @@ -488,6 +557,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.Services/Jobs/Templates/MassEmailTemplate.cs b/Ombi.Services/Jobs/Templates/MassEmailTemplate.cs new file mode 100644 index 000000000..ea73c027d --- /dev/null +++ b/Ombi.Services/Jobs/Templates/MassEmailTemplate.cs @@ -0,0 +1,58 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: RecentlyAddedTemplate.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.IO; +using System.Text; +using System.Windows.Forms; +using NLog; + +namespace Ombi.Services.Jobs.Templates +{ + public class MassEmailTemplate + { + public string TemplateLocation => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? string.Empty, "Jobs", "Templates", "MassEmailTemplate.html"); + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); + + private const string RecentlyAddedKey = "{@MASSEMAIL}"; + + public string LoadTemplate(string html) + { + try + { + var sb = new StringBuilder(File.ReadAllText(TemplateLocation)); + sb.Replace(RecentlyAddedKey, html); + return sb.ToString(); + } + catch (Exception e) + { + Log.Error(e); + return string.Empty; + } + } + } +} \ No newline at end of file diff --git a/Ombi.Services/Jobs/Templates/MassEmailTemplate.html b/Ombi.Services/Jobs/Templates/MassEmailTemplate.html new file mode 100644 index 000000000..18a724b93 --- /dev/null +++ b/Ombi.Services/Jobs/Templates/MassEmailTemplate.html @@ -0,0 +1,181 @@ + + + + + + Ombi + + + + + + + + + +
  +
+ + + + + + + + + + + +
+ + + + + + + +
+ +
+ {@MASSEMAIL} +
+
+ + + + + + +
+
 
+ + \ No newline at end of file diff --git a/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html b/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html index f5b208138..17766147b 100644 --- a/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html +++ b/Ombi.Services/Jobs/Templates/RecentlyAddedTemplate.html @@ -144,14 +144,14 @@ diff --git a/Ombi.Services/Ombi.Services.csproj b/Ombi.Services/Ombi.Services.csproj index 1735094dd..17093e031 100644 --- a/Ombi.Services/Ombi.Services.csproj +++ b/Ombi.Services/Ombi.Services.csproj @@ -87,6 +87,7 @@ + @@ -107,6 +108,9 @@ + + + @@ -115,7 +119,7 @@ - + @@ -180,6 +184,9 @@ + + PreserveNewest + PreserveNewest 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/Helpers/BaseUrlHelper.cs b/Ombi.UI/Helpers/BaseUrlHelper.cs index 3a153493d..ab8e1f9db 100644 --- a/Ombi.UI/Helpers/BaseUrlHelper.cs +++ b/Ombi.UI/Helpers/BaseUrlHelper.cs @@ -333,6 +333,7 @@ namespace Ombi.UI.Helpers { url = $"/{content}{url}"; } + var returnString = context.Request.Path == url ? $"
  • {title}
  • " : $"
  • {title}
  • "; @@ -347,7 +348,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}
  • "; @@ -365,6 +373,12 @@ namespace Ombi.UI.Helpers return helper.Raw(GetCustomizationSettings().ApplicationName); } + public static IHtmlString GetMediaServerName(this HtmlHelpers helper) + { + var s = GetEmbySettings(); + return helper.Raw(s.Enable ? "Emby" : "Plex"); + } + private static string GetBaseUrl() { return GetSettings().BaseUrl; @@ -382,7 +396,7 @@ namespace Ombi.UI.Helpers private static CustomizationSettings GetCustomizationSettings() { - var returnValue = Cache.GetOrSet(CacheKeys.GetPlexRequestSettings, () => + var returnValue = Cache.GetOrSet(CacheKeys.GetCustomizationSettings, () => { var settings = Locator.Resolve>().GetSettings(); return settings; @@ -390,6 +404,16 @@ namespace Ombi.UI.Helpers return returnValue; } + private static EmbySettings GetEmbySettings() + { + var returnValue = Cache.GetOrSet(CacheKeys.GetEmbySettings, () => + { + var settings = Locator.Resolve>().GetSettings(); + return settings; + }); + return returnValue; + } + private static string GetLinkUrl(string assetLocation) { return string.IsNullOrEmpty(assetLocation) ? string.Empty : $"{assetLocation}"; diff --git a/Ombi.UI/Jobs/Scheduler.cs b/Ombi.UI/Jobs/Scheduler.cs index 25151b59f..b0f5266cd 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(), @@ -304,7 +305,7 @@ namespace Ombi.UI.Jobs var embyEpisode = TriggerBuilder.Create() .WithIdentity("EmbyEpisodeCacher", "Emby") - //.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/Models/SearchLoadViewModel.cs b/Ombi.UI/Models/SearchLoadViewModel.cs index 2bdf5078c..667906431 100644 --- a/Ombi.UI/Models/SearchLoadViewModel.cs +++ b/Ombi.UI/Models/SearchLoadViewModel.cs @@ -32,6 +32,8 @@ namespace Ombi.UI.Models public class SearchLoadViewModel { public PlexRequestSettings Settings { get; set; } + public bool Plex { get; set; } + public bool Emby { get; set; } public CustomizationSettings CustomizationSettings { get; set; } } } \ No newline at end of file diff --git a/Ombi.UI/Modules/Admin/AdminModule.cs b/Ombi.UI/Modules/Admin/AdminModule.cs index a83ff8bd1..c9bce2faf 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; @@ -92,6 +93,7 @@ namespace Ombi.UI.Modules.Admin private IJobRecord JobRecorder { get; } private IAnalytics Analytics { get; } private IRecentlyAdded RecentlyAdded { get; } + private IMassEmail MassEmail { get; } private ISettingsService NotifySettings { get; } private ISettingsService DiscordSettings { get; } private IDiscordApi DiscordApi { get; } @@ -123,7 +125,7 @@ namespace Ombi.UI.Modules.Admin ICacheProvider cache, ISettingsService slackSettings, ISlackApi slackApi, ISettingsService lp, ISettingsService scheduler, IJobRecord rec, IAnalytics analytics, - ISettingsService notifyService, IRecentlyAdded recentlyAdded, + ISettingsService notifyService, IRecentlyAdded recentlyAdded, IMassEmail massEmail, ISettingsService watcherSettings , ISettingsService discord, IDiscordApi discordapi, ISettingsService settings, IRadarrApi radarrApi, @@ -158,6 +160,7 @@ namespace Ombi.UI.Modules.Admin Analytics = analytics; NotifySettings = notifyService; RecentlyAdded = recentlyAdded; + MassEmail = massEmail; WatcherSettings = watcherSettings; DiscordSettings = discord; DiscordApi = discordapi; @@ -222,6 +225,9 @@ namespace Ombi.UI.Modules.Admin Get["/newsletter", true] = async (x, ct) => await Newsletter(); Post["/newsletter", true] = async (x, ct) => await SaveNewsletter(); + Post["/testnewsletteradminemail"] = x => TestNewsletterAdminEmail(); + Post["/testmassadminemail"] = x => TestMassAdminEmail(); + Post["/sendmassemail"] = x => SendMassEmail(); Post["/createapikey"] = x => CreateApiKey(); @@ -246,7 +252,6 @@ namespace Ombi.UI.Modules.Admin Get["/notificationsettings", true] = async (x, ct) => await NotificationSettings(); Post["/notificationsettings"] = x => SaveNotificationSettings(); - Post["/recentlyAddedTest"] = x => RecentlyAddedTest(); } private async Task Authentication() @@ -441,11 +446,15 @@ namespace Ombi.UI.Modules.Admin private async Task SavePlex() { var plexSettings = this.Bind(); - var valid = this.Validate(plexSettings); - if (!valid.IsValid) - { - return Response.AsJson(valid.SendJsonError()); - } + + if (plexSettings.Enable) + { + var valid = this.Validate(plexSettings); + if (!valid.IsValid) + { + return Response.AsJson(valid.SendJsonError()); + } + } if (plexSettings.Enable) @@ -462,7 +471,7 @@ namespace Ombi.UI.Modules.Admin } } - if (string.IsNullOrEmpty(plexSettings.MachineIdentifier)) + if (string.IsNullOrEmpty(plexSettings.MachineIdentifier) && plexSettings.Enable) { //Lookup identifier var server = PlexApi.GetServer(plexSettings.PlexAuthToken); @@ -815,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 @@ -1133,6 +1146,8 @@ namespace Ombi.UI.Modules.Admin var emby = await EmbySettings.GetSettingsAsync(); var plex = await PlexService.GetSettingsAsync(); + + var dict = new Dictionary(); @@ -1145,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); + } } } @@ -1166,7 +1198,13 @@ namespace Ombi.UI.Modules.Admin FaultQueueHandler = s.FaultQueueHandler, PlexEpisodeCacher = s.PlexEpisodeCacher, PlexUserChecker = s.PlexUserChecker, - UserRequestLimitResetter = s.UserRequestLimitResetter + UserRequestLimitResetter = s.UserRequestLimitResetter, + EmbyAvailabilityChecker = s.EmbyAvailabilityChecker, + EmbyContentCacher = s.EmbyContentCacher, + EmbyEpisodeCacher = s.EmbyEpisodeCacher, + EmbyUserChecker = s.EmbyUserChecker, + RadarrCacher = s.RadarrCacher, + WatcherCacher = s.WatcherCacher }; return View["SchedulerSettings", model]; } @@ -1229,13 +1267,35 @@ namespace Ombi.UI.Modules.Admin var model = this.Bind(); return View["NotificationSettings", model]; } - - private Response RecentlyAddedTest() + + private Response TestNewsletterAdminEmail() + { + try + { + Log.Debug("Clicked Admin Newsletter Email Test"); + RecentlyAdded.RecentlyAddedAdminTest(); + return Response.AsJson(new JsonResponseModel { Result = true, Message = "Sent email to administrator" }); + } + catch (Exception e) + { + Log.Error(e); + return Response.AsJson(new JsonResponseModel { Result = false, Message = e.Message }); + } + } + private Response TestMassAdminEmail() { try { - Log.Debug("Clicked TEST"); - RecentlyAdded.Test(); + var settings = this.Bind(); + Log.Debug("Clicked Admin Mass Email Test"); + if (settings.Subject == null) { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Please Set a Subject" }); + } + if (settings.Body == null) + { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Please Set a Body" }); + } + MassEmail.MassEmailAdminTest(settings.Body.Replace("\n", "
    "), settings.Subject); return Response.AsJson(new JsonResponseModel { Result = true, Message = "Sent email to administrator" }); } catch (Exception e) @@ -1244,5 +1304,28 @@ namespace Ombi.UI.Modules.Admin return Response.AsJson(new JsonResponseModel { Result = false, Message = e.Message }); } } + private Response SendMassEmail() + { + try + { + var settings = this.Bind(); + Log.Debug("Clicked Admin Mass Email Test"); + if (settings.Subject == null) + { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Please Set a Subject" }); + } + if (settings.Body == null) + { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Please Set a Body" }); + } + MassEmail.SendMassEmail(settings.Body.Replace("\n", "
    "), settings.Subject); + return Response.AsJson(new JsonResponseModel { Result = true, Message = "Sent email to All users" }); + } + catch (Exception e) + { + Log.Error(e); + return Response.AsJson(new JsonResponseModel { Result = false, Message = e.Message }); + } + } } } \ No newline at end of file diff --git a/Ombi.UI/Modules/Admin/IntegrationModule.cs b/Ombi.UI/Modules/Admin/IntegrationModule.cs index 36ec5fcc9..4076f9756 100644 --- a/Ombi.UI/Modules/Admin/IntegrationModule.cs +++ b/Ombi.UI/Modules/Admin/IntegrationModule.cs @@ -156,7 +156,7 @@ namespace Ombi.UI.Modules.Admin var cp = await CpSettings.GetSettingsAsync(); if (cp.Enabled) { - return Response.AsJson(new JsonResponseModel { Result = false, Message = "CouchPotato is enabled, we cannot enable Watcher and CouchPotato" }); + return Response.AsJson(new JsonResponseModel { Result = false, Message = "CouchPotato is enabled, we cannot enable Radarr and CouchPotato" }); } var valid = this.Validate(radarrSettings); 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)) { diff --git a/Ombi.UI/Modules/SearchModule.cs b/Ombi.UI/Modules/SearchModule.cs index 20b43097d..59db65270 100644 --- a/Ombi.UI/Modules/SearchModule.cs +++ b/Ombi.UI/Modules/SearchModule.cs @@ -69,7 +69,7 @@ namespace Ombi.UI.Modules { public class SearchModule : BaseAuthModule { - public SearchModule(ICacheProvider cache, + public SearchModule(ICacheProvider cache, ISettingsService prSettings, IAvailabilityChecker plexChecker, IRequestService request, ISonarrApi sonarrApi, ISettingsService sonarrSettings, ISettingsService sickRageService, ISickRageApi srApi, @@ -141,7 +141,7 @@ namespace Ombi.UI.Modules async (x, ct) => await RequestTvShow((int)Request.Form.tvId, (string)Request.Form.seasons); Post["request/tvEpisodes", true] = async (x, ct) => await RequestTvShow(0, "episode"); Post["request/album", true] = async (x, ct) => await RequestAlbum((string)Request.Form.albumId); - + Get["/seasons"] = x => GetSeasons(); Get["/episodes", true] = async (x, ct) => await GetEpisodes(); } @@ -187,10 +187,14 @@ namespace Ombi.UI.Modules var settings = await PrService.GetSettingsAsync(); var custom = await CustomizationSettings.GetSettingsAsync(); + var emby = await EmbySettings.GetSettingsAsync(); + var plex = await PlexService.GetSettingsAsync(); var searchViewModel = new SearchLoadViewModel { Settings = settings, - CustomizationSettings = custom + CustomizationSettings = custom, + Emby = emby.Enable, + Plex = plex.Enable }; @@ -300,11 +304,11 @@ namespace Ombi.UI.Modules VoteAverage = movie.VoteAverage, VoteCount = movie.VoteCount }; - + if (counter <= 5) // Let's only do it for the first 5 items { var movieInfo = MovieApi.GetMovieInformationWithVideos(movie.Id); - + // TODO needs to be careful about this, it's adding extra time to search... // https://www.themoviedb.org/talk/5807f4cdc3a36812160041f2 viewMovie.ImdbId = movieInfo?.imdb_id; @@ -400,11 +404,11 @@ namespace Ombi.UI.Modules case ShowSearchType.Popular: Analytics.TrackEventAsync(Category.Search, Action.TvShow, "Popular", Username, CookieHelper.GetAnalyticClientId(Cookies)); var popularShows = await TraktApi.GetPopularShows(); - + foreach (var popularShow in popularShows) { var theTvDbId = int.Parse(popularShow.Ids.Tvdb.ToString()); - + var model = new SearchTvShowViewModel { FirstAired = popularShow.FirstAired?.ToString("yyyy-MM-ddTHH:mm:ss"), @@ -577,6 +581,7 @@ namespace Ombi.UI.Modules Analytics.TrackEventAsync(Category.Search, Action.TvShow, searchTerm, Username, CookieHelper.GetAnalyticClientId(Cookies)); var plexSettings = await PlexService.GetSettingsAsync(); + var embySettings = await EmbySettings.GetSettingsAsync(); var prSettings = await PrService.GetSettingsAsync(); var providerId = string.Empty; @@ -600,6 +605,8 @@ namespace Ombi.UI.Modules var sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays var content = PlexContentRepository.GetAll(); var plexTvShows = PlexChecker.GetPlexTvShows(content); + var embyContent = EmbyContentRepository.GetAll(); + var embyCached = EmbyChecker.GetEmbyTvShows(embyContent); var viewTv = new List(); foreach (var t in apiTv) @@ -633,20 +640,28 @@ namespace Ombi.UI.Modules EnableTvRequestsForOnlySeries = (prSettings.DisableTvRequestsByEpisode && prSettings.DisableTvRequestsBySeason) }; + providerId = viewT.Id.ToString(); - if (plexSettings.AdvancedSearch) + if (embySettings.Enable) { - providerId = viewT.Id.ToString(); + var embyShow = EmbyChecker.GetTvShow(embyCached.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), providerId); + if (embyShow != null) + { + viewT.Available = true; + } } - - var plexShow = PlexChecker.GetTvShow(plexTvShows.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), - providerId); - if (plexShow != null) + if (plexSettings.Enable) { - viewT.Available = true; - viewT.PlexUrl = plexShow.Url; + var plexShow = PlexChecker.GetTvShow(plexTvShows.ToArray(), t.show.name, t.show.premiered?.Substring(0, 4), + providerId); + if (plexShow != null) + { + viewT.Available = true; + viewT.PlexUrl = plexShow.Url; + } } - else if (t.show?.externals?.thetvdb != null) + + if (t.show?.externals?.thetvdb != null && !viewT.Available) { var tvdbid = (int)t.show.externals.thetvdb; if (dbTv.ContainsKey(tvdbid)) @@ -747,7 +762,7 @@ namespace Ombi.UI.Modules Message = "You have reached your weekly request limit for Movies! Please contact your admin." }); } - + var embySettings = await EmbySettings.GetSettingsAsync(); Analytics.TrackEventAsync(Category.Search, Action.Request, "Movie", Username, CookieHelper.GetAnalyticClientId(Cookies)); var movieInfo = await MovieApi.GetMovieInformation(movieId); @@ -806,7 +821,7 @@ namespace Ombi.UI.Modules Response.AsJson(new JsonResponseModel { Result = false, - Message = string.Format(Resources.UI.Search_CouldNotCheckPlex, fullMovieName) + Message = string.Format(Resources.UI.Search_CouldNotCheckPlex, fullMovieName,GetMediaServerName()) }); } //#endif @@ -851,7 +866,7 @@ namespace Ombi.UI.Modules } if (!result.MovieSendingEnabled) { - + return await AddRequest(model, settings, $"{fullMovieName} {Resources.UI.Search_SuccessfullyAdded}"); } @@ -946,7 +961,7 @@ namespace Ombi.UI.Modules }); } } - + var embySettings = await EmbySettings.GetSettingsAsync(); var showInfo = TvApi.ShowLookupByTheTvDbId(showId); DateTime firstAir; DateTime.TryParse(showInfo.premiered, out firstAir); @@ -1053,7 +1068,7 @@ namespace Ombi.UI.Modules Response.AsJson(new JsonResponseModel { Result = false, - Message = $"{fullShowName} {Resources.UI.Search_AlreadyInPlex}" + Message = $"{fullShowName} {string.Format(Resources.UI.Search_AlreadyInPlex,embySettings.Enable ? "Emby" : "Plex")}" }); } } @@ -1099,7 +1114,7 @@ namespace Ombi.UI.Modules { Result = false, Message = - $"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {Resources.UI.Search_AlreadyInPlex}" + $"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {string.Format(Resources.UI.Search_AlreadyInPlex,GetMediaServerName())}" }); } } @@ -1121,7 +1136,7 @@ namespace Ombi.UI.Modules Response.AsJson(new JsonResponseModel { Result = false, - Message = $"{fullShowName} {Resources.UI.Search_AlreadyInPlex}" + Message = $"{fullShowName} {string.Format(Resources.UI.Search_AlreadyInPlex,GetMediaServerName())}" }); } } @@ -1134,12 +1149,11 @@ namespace Ombi.UI.Modules Response.AsJson(new JsonResponseModel { Result = false, - Message = $"{fullShowName} {Resources.UI.Search_AlreadyInPlex}" + Message = $"{fullShowName} {string.Format(Resources.UI.Search_AlreadyInPlex,GetMediaServerName())}" }); } } } - var embySettings = await EmbySettings.GetSettingsAsync(); if (embySettings.Enable) { var embyContent = EmbyContentRepository.GetAll(); @@ -1162,7 +1176,7 @@ namespace Ombi.UI.Modules { Result = false, Message = - $"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {Resources.UI.Search_AlreadyInPlex}" + $"{fullShowName} {d.SeasonNumber} - {d.EpisodeNumber} {string.Format(Resources.UI.Search_AlreadyInPlex,GetMediaServerName())}" }); } } @@ -1200,7 +1214,7 @@ namespace Ombi.UI.Modules Message = $"{fullShowName} is already in Emby!" }); } - } + } } } catch (Exception) @@ -1209,7 +1223,7 @@ namespace Ombi.UI.Modules Response.AsJson(new JsonResponseModel { Result = false, - Message = string.Format(Resources.UI.Search_CouldNotCheckPlex, fullShowName) + Message = string.Format(Resources.UI.Search_CouldNotCheckPlex, fullShowName,GetMediaServerName()) }); } @@ -1445,7 +1459,7 @@ namespace Ombi.UI.Modules return img; } - + private Response GetSeasons() { var seriesId = (int)Request.Query.tvId; @@ -1780,6 +1794,12 @@ namespace Ombi.UI.Modules return Response.AsJson(new JsonResponseModel { Result = false, Message = Resources.UI.Search_TvNotSetUp }); } + + private string GetMediaServerName() + { + var e = EmbySettings.GetSettings(); + return e.Enable ? "Emby" : "Plex"; + } } } diff --git a/Ombi.UI/NinjectModules/ServicesModule.cs b/Ombi.UI/NinjectModules/ServicesModule.cs index 95dfcf433..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,7 +49,8 @@ namespace Ombi.UI.NinjectModules Bind().To(); Bind().To(); Bind().To(); - Bind().To(); + Bind().To(); + Bind().To(); Bind().To(); Bind().To(); Bind().To(); @@ -64,6 +66,7 @@ namespace Ombi.UI.NinjectModules Bind().To(); Bind().To(); Bind().To(); + Bind().To(); Bind().To(); diff --git a/Ombi.UI/Resources/UI.da.resx b/Ombi.UI/Resources/UI.da.resx index bb2efd6bf..e4164aeed 100644 --- a/Ombi.UI/Resources/UI.da.resx +++ b/Ombi.UI/Resources/UI.da.resx @@ -121,13 +121,13 @@ Log ind - Ønsker du at se en film eller tv-show, men det er i øjeblikket ikke på Plex? Log nedenfor med dit Plex.tv brugernavn og password !! + Ønsker du at se en film eller tv-show, men det er i øjeblikket ikke på {0}? Log nedenfor med dit brugernavn og password !! Dine login-oplysninger bruges kun til at godkende din Plex konto. - Plex.tv Brugernavn + Brugernavn Brugernavn @@ -211,7 +211,7 @@ Album - Ønsker at se noget, der ikke i øjeblikket på Plex ?! Intet problem! Bare søge efter det nedenfor og anmode den ! + Ønsker at se noget, der ikke i øjeblikket på {0}?! Intet problem! Bare søge efter det nedenfor og anmode den ! Søg @@ -409,7 +409,7 @@ allerede er blevet anmodet !! - Vi kunne ikke kontrollere, om {0} er i Plex, er du sikker på det er korrekt setup ?! + Vi kunne ikke kontrollere, om {0} er i {1}, er du sikker på det er korrekt setup ?! Noget gik galt tilføjer filmen til CouchPotato! Tjek venligst din opsætning.! @@ -418,7 +418,7 @@ Du har nået din ugentlige anmodning grænse for film! Kontakt din administrator.! - er allerede i Plex !! + er allerede i {0}!! Noget gik galt tilføjer filmen til SickRage! Tjek venligst din opsætning.! @@ -435,9 +435,6 @@ Du har nået din ugentlige anmodning grænse for tv-shows! Kontakt din administrator.! - - Beklager, men denne funktionalitet er i øjeblikket kun for brugere med Plex konti! - Beklager, men din administrator har endnu ikke gjort det muligt denne funktionalitet.! diff --git a/Ombi.UI/Resources/UI.de.resx b/Ombi.UI/Resources/UI.de.resx index 1cd1d0192..5b908f1b8 100644 --- a/Ombi.UI/Resources/UI.de.resx +++ b/Ombi.UI/Resources/UI.de.resx @@ -121,13 +121,13 @@ Anmelden - Möchten Sie einen Film oder eine Serie schauen, die momentan noch nicht auf Plex ist? Dann loggen Sie sich unten ein und fordern Sie das Material an! + Möchten Sie einen Film oder eine Serie schauen, die momentan noch nicht auf {0}ist? Dann loggen Sie sich unten ein und fordern Sie das Material an! Ihre Login-Daten werden nur zur Authorisierung Ihres Plex-Konto verwendet. - Plex.tv Benutzername + Benutzername Benutzername @@ -211,7 +211,7 @@ Alben - Möchten Sie etwas schauen, das derzeit nicht auf Plex ist?! Kein Problem! Suchen Sie unten einfach danach und fragen Sie es an! + Möchten Sie etwas schauen, das derzeit nicht auf {0} ist?! Kein Problem! Suchen Sie unten einfach danach und fragen Sie es an! Suche @@ -409,7 +409,7 @@ wurde bereits angefragt! - Wir konnten nicht prüfen ob {0} bereits auf Plex ist. Bist du sicher dass alles richtig installiert ist? + Wir konnten nicht prüfen ob {0} bereits auf {1}ist. Bist du sicher dass alles richtig installiert ist? Etwas ging etwas schief beim hinzufügen des Filmes zu CouchPotato! Bitte überprüfe deine Einstellungen. @@ -418,7 +418,7 @@ Du hast deine wöchentliche Maximalanfragen für neue Filme erreicht. Bitte kontaktiere den Administrator. - ist bereits auf Plex! + ist bereits auf {0}! Etwas ging etwas schief beim hinzufügen des Filmes zu SickRage! Bitte überprüfe deine Einstellungen. @@ -435,9 +435,6 @@ Du hast deine wöchentliche Maximalanfragen für neue Serien erreicht. Bitte kontaktiere den Administrator. - - Entschuldige, aber diese Funktion ist momentan nur für Benutzer mit Plex-Accounts freigeschaltet. - Entschuldige, aber dein Administrator hat diese Funktion noch nicht freigeschaltet. diff --git a/Ombi.UI/Resources/UI.es.resx b/Ombi.UI/Resources/UI.es.resx index dd325f2bb..c00323af5 100644 --- a/Ombi.UI/Resources/UI.es.resx +++ b/Ombi.UI/Resources/UI.es.resx @@ -121,13 +121,13 @@ INICIAR SESIÓN - ¿Quieres ver una película o programa de televisión, pero no es actualmente en Plex? Ingresa abajo con su nombre de usuario y contraseña Plex.tv ! + ¿Quieres ver una película o programa de televisión, pero no es actualmente en {0}? Ingresa abajo con su nombre de usuario y contraseña ! Sus datos de acceso sólo se utilizan para autenticar su cuenta Plex. - Plex.tv nombre de usuario + nombre de usuario Username @@ -211,7 +211,7 @@ Álbumes - ¿Quieres ver algo que no se encuentra actualmente en Plex ?! ¡No hay problema! Sólo la búsqueda de abajo y que solicitarlo ! + ¿Quieres ver algo que no se encuentra actualmente en {0}?! ¡No hay problema! Sólo la búsqueda de abajo y que solicitarlo ! Buscar @@ -409,7 +409,7 @@ ya ha sido solicitada !! - No hemos podido comprobar si {0} está en Plex, ¿estás seguro de que es correcta la configuración ?! + No hemos podido comprobar si {0} está en {1}, ¿estás seguro de que es correcta la configuración ?! Algo salió mal la adición de la película para CouchPotato! Por favor verifica la configuracion.! @@ -418,7 +418,7 @@ Ha llegado a su límite de solicitudes semanales de películas! Por favor, póngase en contacto con su administrador.! - ya está en Plex !! + ya está en {0}!! Algo salió mal la adición de la película para SickRage! Por favor verifica la configuracion.! @@ -435,9 +435,6 @@ Ha llegado a su límite de solicitudes semanales de programas de televisión! Por favor, póngase en contacto con su administrador.! - - Lo sentimos, pero esta funcionalidad es actualmente sólo para los usuarios con cuentas Plex! - Lo sentimos, pero el administrador aún no ha habilitado esta funcionalidad.! diff --git a/Ombi.UI/Resources/UI.fr.resx b/Ombi.UI/Resources/UI.fr.resx index 11f787a36..e9a461b23 100644 --- a/Ombi.UI/Resources/UI.fr.resx +++ b/Ombi.UI/Resources/UI.fr.resx @@ -121,13 +121,13 @@ Connexion - Vous souhaitez avoir accès à un contenu qui n'est pas encore disponible dans Plex ? Demandez-le ici ! + Vous souhaitez avoir accès à un contenu qui n'est pas encore disponible dans {0}? Demandez-le ici ! Vos informations de connexion sont uniquement utilisées pour authentifier votre compte Plex. - Nom d'utilisateur Plex.tv + Nom d'utilisateur Nom d’utilisateur @@ -211,7 +211,7 @@ Albums - Vous souhaitez avoir accès à un contenu qui n'est pas encore disponible dans Plex ?! Aucun problème ! Il suffit d'effectuer une recherche ci-dessous et d'en faire la demande! + Vous souhaitez avoir accès à un contenu qui n'est pas encore disponible dans {0} ?! Aucun problème ! Il suffit d'effectuer une recherche ci-dessous et d'en faire la demande! Rechercher @@ -409,7 +409,7 @@ a déjà été demandé! - Nous ne pouvons pas vérifier que {0} est présent dans Plex, êtes-vous sûr que la configuration est correcte? + Nous ne pouvons pas vérifier que {0} est présent dans {1}, êtes-vous sûr que la configuration est correcte? Une erreur s'est produite lors de l'ajout du film dans CouchPotato! Merci de bien vouloir vérifier vos paramètres. @@ -418,7 +418,7 @@ Vous avez atteint votre quota hebdomadaire de demandes pour les films! Merci de bien vouloir contacter l'administrateur. - est déjà présent dans Plex! + est déjà présent dans {0}! Une erreur s'est produite lors de l'ajout de la série TV dans SickRage! Merci de bien vouloir vérifier vos paramètres. @@ -435,9 +435,6 @@ Vous avez atteint votre quota hebdomadaire de demandes pour les séries TV! Merci de bien vouloir contacter l'administrateur. - - Désolé mais cette fonctionnalité est réservée aux utilisateurs possédant un compte Plex. - Désolé mais l'administrateur n'a pas encore activé cette fonctionnalité. diff --git a/Ombi.UI/Resources/UI.it.resx b/Ombi.UI/Resources/UI.it.resx index 3dd1640c4..3613c3356 100644 --- a/Ombi.UI/Resources/UI.it.resx +++ b/Ombi.UI/Resources/UI.it.resx @@ -121,13 +121,13 @@ Accesso - Vuoi guardare un film o una serie tv ma non è attualmente in Plex? Effettua il login con il tuo username e la password Plex.tv ! + Vuoi guardare un film o una serie tv ma non è attualmente in {0}? Effettua il login con il tuo username e la password ! I dati di accesso vengono utilizzati solo per autenticare l'account Plex. - Plex.tv Nome utente + Nome utente Nome utente @@ -214,7 +214,7 @@ Msuica - Vuoi guardare qualcosa che non è attualmente in Plex?! Non c'è problema! Basta cercarla qui sotto e richiederla! + Vuoi guardare qualcosa che non è attualmente in {0}?! Non c'è problema! Basta cercarla qui sotto e richiederla! Suggerimenti @@ -409,7 +409,7 @@ è già stato richiesto! - Non siamo riusciti a controllare se {0} è in Plex, sei sicuro che sia configurato correttamente? + Non siamo riusciti a controllare se {0} è in {1}, sei sicuro che sia configurato correttamente? Qualcosa è andato storto aggiungendo il film a CouchPotato! Controlla le impostazioni @@ -418,7 +418,7 @@ Hai raggiunto il numero massimo di richieste settimanali per i Film! Contatta l'amministratore - è già disponibile in Plex! + è già disponibile in {0}! Qualcosa è andato storto aggiungendo il film a SickRage! Controlla le impostazioni @@ -435,9 +435,6 @@ Hai raggiunto il numero massimo di richieste settimanali per le Serie TV! Contatta l'amministratore - - Spiacente, ma questa funzione è disponibile solo per gli utenti con un account Plex. - Spiacente, ma l'amministratore non ha ancora abilitato questa funzionalità. diff --git a/Ombi.UI/Resources/UI.nl.resx b/Ombi.UI/Resources/UI.nl.resx index 0b85e2aa9..3761a96cc 100644 --- a/Ombi.UI/Resources/UI.nl.resx +++ b/Ombi.UI/Resources/UI.nl.resx @@ -121,13 +121,13 @@ Inloggen - Wilt u een film of een tv serie kijken, maar staat deze niet op Plex? Log hieronder in met uw gebruikersnaam en wachtwoord van Plex.tv + Wilt u een film of een tv serie kijken, maar staat deze niet op {0}? Log hieronder in met uw gebruikersnaam en wachtwoord van Uw login gegevens worden alleen gebruikt om uw account te verifiëren bij Plex. - Plex.tv Gebruikersnaam + Gebruikersnaam Gebruikersnaam @@ -217,7 +217,7 @@ Albums - Wilt u kijken naar iets dat dat momenteel niet op Plex is?! Geen probleem! zoek hieronder en vraag het aan! + Wilt u kijken naar iets dat dat momenteel niet op {0} is?! Geen probleem! zoek hieronder en vraag het aan! Suggesties @@ -409,10 +409,7 @@ Is al aangevraagd! - Staat al op Plex! - - - Sorry, deze functie is momenteel alleen voor gebruikers met een Plex account. + Staat al op {0}! Sorry, uw administrator heeft deze functie nog niet geactiveerd. @@ -424,7 +421,7 @@ Kon niet opslaan, probeer het later nog eens. - We konden niet controleren of {0} al in plex bestaat, weet je zeker dat het correct is ingesteld? + We konden niet controleren of {0} al in {1} bestaat, weet je zeker dat het correct is ingesteld? Er is iets foutgegaan tijdens het toevoegen van de film aan CouchPotato! Controleer je instellingen diff --git a/Ombi.UI/Resources/UI.pt.resx b/Ombi.UI/Resources/UI.pt.resx index b265ea445..681a11549 100644 --- a/Ombi.UI/Resources/UI.pt.resx +++ b/Ombi.UI/Resources/UI.pt.resx @@ -121,13 +121,13 @@ Entrar - Quer assistir a um filme ou programa de TV, mas não está atualmente em Plex? Entre abaixo com seu nome de usuário e senha Plex.tv !! + Quer assistir a um filme ou programa de TV, mas não está atualmente em {0}? Entre abaixo com seu nome de usuário e senha ! Seus dados de login são apenas usados ​​para autenticar sua conta Plex.! - Plex.tv usuário + usuário Nome de usuário @@ -211,7 +211,7 @@ Álbuns - Quer assistir algo que não está atualmente em Plex ?! Sem problemas! Basta procurá-lo abaixo e solicitá-lo !! + Quer assistir algo que não está atualmente em {0}?! Sem problemas! Basta procurá-lo abaixo e solicitá-lo !! Buscar @@ -409,7 +409,7 @@ já foi solicitado !! - Nós não poderia verificar se {0} está em Plex, você tem certeza que é configurada corretamente ?! + Nós não poderia verificar se {0} está em {1}, você tem certeza que é configurada corretamente ?! Algo deu errado adicionando o filme para CouchPotato! Verifique as suas opções.! @@ -418,7 +418,7 @@ Atingiu seu limite semanal de solicitação para filmes! Entre em contato com seu administrador. - Já está no Plex! + Já está no {0}! Algo deu errado adicionar o filme para SickRage! Por favor, verifique suas configurações. @@ -435,9 +435,6 @@ Atingiu seu limite semanal de solicitação para programas de TV! Entre em contato com seu administrador. - - Desculpe, mas essa funcionalidade é atualmente somente para os usuários com contas de Plex - Desculpe, mas o administrador não permitiu ainda esta funcionalidade. diff --git a/Ombi.UI/Resources/UI.resx b/Ombi.UI/Resources/UI.resx index d24c5ea1c..a9f63e0e8 100644 --- a/Ombi.UI/Resources/UI.resx +++ b/Ombi.UI/Resources/UI.resx @@ -101,14 +101,14 @@ Login - Want to watch a movie or tv show but it's not currently on Plex? - Login below with your Plex.tv username and password! + Want to watch a movie or tv show but it's not currently on {0}? + Login below with your username and password! Your login details are only used to authenticate your Plex account. - Plex.tv Username + Username Username @@ -192,7 +192,7 @@ Albums - Want to watch something that is not currently on Plex?! No problem! Just search for it below and request it! + Want to watch something that is not currently on {0}?! No problem! Just search for it below and request it! Search @@ -390,7 +390,7 @@ has already been requested! - We could not check if {0} is in Plex, are you sure it's correctly setup? + We could not check if {0} is in {1}, are you sure it's correctly setup? Something went wrong adding the movie to CouchPotato! Please check your settings. @@ -399,7 +399,7 @@ You have reached your weekly request limit for Movies! Please contact your admin. - is already in Plex! + is already in {0}! Something went wrong adding the movie to SickRage! Please check your settings. @@ -416,9 +416,6 @@ You have reached your weekly request limit for TV Shows! Please contact your admin. - - Sorry, but this functionality is currently only for users with Plex accounts - Sorry, but your administrator has not yet enabled this functionality. @@ -468,7 +465,7 @@ TV show status - Currently we are indexing all of the available tv shows and movies on the Plex server, so there might be some unexpected behavior. This shouldn't take too long. + Currently we are indexing all of the available tv shows and movies on the media server, so there might be some unexpected behavior. This shouldn't take too long. User Management diff --git a/Ombi.UI/Resources/UI.sv.resx b/Ombi.UI/Resources/UI.sv.resx index 4c70109c7..3d21b5df0 100644 --- a/Ombi.UI/Resources/UI.sv.resx +++ b/Ombi.UI/Resources/UI.sv.resx @@ -121,13 +121,13 @@ Logga in - Vill du titta på en film eller TV-show, men det är inte närvarande på Plex? Logga in nedan med Plex.tv användarnamn och lösenord !! + Vill du titta på en film eller TV-show, men det är inte närvarande på {0}? Logga in nedan med användarnamn och lösenord !! Dina inloggningsuppgifter används endast för att autentisera ditt Plex-konto. - Plex.tv användarnamn + Användarnamn Användarnamn @@ -214,7 +214,7 @@ Album - Vill titta på något som inte är närvarande på Plex ?! Inga problem! Bara söka efter den nedan och begär det ! + Vill titta på något som inte är närvarande på {0}?! Inga problem! Bara söka efter den nedan och begär det ! Sök @@ -409,7 +409,7 @@ har redan begärts - Vi kunde inte kontrollera om {0} är i Plex, är du säker det är korrekt installation? + Vi kunde inte kontrollera om {0} är i {1}, är du säker det är korrekt installation? Något gick fel att lägga till filmen i CouchPotato! Kontrollera inställningarna. @@ -418,7 +418,7 @@ Du har nått din weekly begäran gräns för filmer! Kontakta din admin. - är redan i Plex + är redan i {0} Något gick fel att lägga till filmen i SickRage! Kontrollera inställningarna. @@ -435,9 +435,6 @@ Du har nått din weekly begäran gräns för TV-program! Kontakta din admin. - - Ledsen, men denna funktion är för närvarande endast för användare med Plex konton - Ledsen, men administratören har ännu inte aktiverat denna funktion. diff --git a/Ombi.UI/Resources/UI1.Designer.cs b/Ombi.UI/Resources/UI1.Designer.cs index 56013a95f..4920f2e7f 100644 --- a/Ombi.UI/Resources/UI1.Designer.cs +++ b/Ombi.UI/Resources/UI1.Designer.cs @@ -223,7 +223,7 @@ namespace Ombi.UI.Resources { } /// - /// Looks up a localized string similar to Currently we are indexing all of the available tv shows and movies on the Plex server, so there might be some unexpected behavior. This shouldn't take too long.. + /// Looks up a localized string similar to Currently we are indexing all of the available tv shows and movies on the media server, so there might be some unexpected behavior. This shouldn't take too long.. /// public static string Layout_CacherRunning { get { @@ -736,7 +736,7 @@ namespace Ombi.UI.Resources { } /// - /// Looks up a localized string similar to is already in Plex!. + /// Looks up a localized string similar to is already in {0}!. /// public static string Search_AlreadyInPlex { get { @@ -790,7 +790,7 @@ namespace Ombi.UI.Resources { } /// - /// Looks up a localized string similar to We could not check if {0} is in Plex, are you sure it's correctly setup?. + /// Looks up a localized string similar to We could not check if {0} is in {1}, are you sure it's correctly setup?. /// public static string Search_CouldNotCheckPlex { get { @@ -816,15 +816,6 @@ namespace Ombi.UI.Resources { } } - /// - /// Looks up a localized string similar to Sorry, but this functionality is currently only for users with Plex accounts. - /// - public static string Search_ErrorPlexAccountOnly { - get { - return ResourceManager.GetString("Search_ErrorPlexAccountOnly", resourceCulture); - } - } - /// /// Looks up a localized string similar to First Season. /// @@ -907,7 +898,7 @@ namespace Ombi.UI.Resources { } /// - /// Looks up a localized string similar to Want to watch something that is not currently on Plex?! No problem! Just search for it below and request it!. + /// Looks up a localized string similar to Want to watch something that is not currently on {0}?! No problem! Just search for it below and request it!. /// public static string Search_Paragraph { get { @@ -1132,8 +1123,8 @@ namespace Ombi.UI.Resources { } /// - /// Looks up a localized string similar to Want to watch a movie or tv show but it's not currently on Plex? - /// Login below with your Plex.tv username and password!. + /// Looks up a localized string similar to Want to watch a movie or tv show but it's not currently on {0}? + /// Login below with your username and password!. /// public static string UserLogin_Paragraph { get { @@ -1178,7 +1169,7 @@ namespace Ombi.UI.Resources { } /// - /// Looks up a localized string similar to Plex.tv Username . + /// Looks up a localized string similar to Username . /// public static string UserLogin_Username { get { diff --git a/Ombi.UI/Views/Admin/Emby.cshtml b/Ombi.UI/Views/Admin/Emby.cshtml index f0b05c979..7ebceaf14 100644 --- a/Ombi.UI/Views/Admin/Emby.cshtml +++ b/Ombi.UI/Views/Admin/Emby.cshtml @@ -47,6 +47,8 @@ + @Html.Checkbox(Model.EnableEpisodeSearching, "EnableEpisodeSearching", "Enable Episode Searching") +
    diff --git a/Ombi.UI/Views/Admin/LandingPage.cshtml b/Ombi.UI/Views/Admin/LandingPage.cshtml index 20ad85c53..e48f5ca92 100644 --- a/Ombi.UI/Views/Admin/LandingPage.cshtml +++ b/Ombi.UI/Views/Admin/LandingPage.cshtml @@ -54,7 +54,7 @@

    Notice Message

    - +
    diff --git a/Ombi.UI/Views/Admin/NewsletterSettings.cshtml b/Ombi.UI/Views/Admin/NewsletterSettings.cshtml index 898a7a761..bf890eb93 100644 --- a/Ombi.UI/Views/Admin/NewsletterSettings.cshtml +++ b/Ombi.UI/Views/Admin/NewsletterSettings.cshtml @@ -7,46 +7,48 @@
    Newsletter Settings +
    - -
    -
    + +
    +
    - Note: This will require you to setup your email notifications -
    - @if (Model.SendRecentlyAddedEmail) - { - - } - else - { - - } + Note: This will require you to setup your email notifications +
    + @if (Model.SendRecentlyAddedEmail) + { + + } + else + { + + } +
    -
    -
    - -
    - - You can add multiple email addresses by using the ; delimiter -
    - +
    + +
    + + You can add multiple email addresses by using the ; delimiter +
    + +
    -
    -
    -
    - +
    +
    + +
    -
    -
    -
    -
    -
    - +
    +
    +
    +
    + +
    @@ -54,6 +56,39 @@
    +
    +
    + Mass Email +
    +
    + Note: This will require you to setup your email notifications +
    +
    + +
    + +
    +
    +
    + + + + Supports HTML + +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    @@ -90,8 +125,8 @@ $('#recentlyAddedBtn').click(function (e) { e.preventDefault(); var base = '@Html.GetBaseUrl()'; - var url = createBaseUrl(base, '/admin/recentlyAddedTest'); - $('#spinner').attr("class", "fa fa-spinner fa-spin"); + var url = createBaseUrl(base, '/admin/testnewsletteradminemail'); + $('#testEmailSpinner').attr("class", "fa fa-spinner fa-spin"); $.ajax({ type: "post", url: url, @@ -99,17 +134,74 @@ success: function (response) { if (response) { generateNotify(response.message, "success"); - $('#spinner').attr("class", "fa fa-check"); + $('#testSendMassEmailSpinner').attr("class", "fa fa-check"); + } else { + + generateNotify(response.message, "danger"); + $('#testSendMassEmailSpinner').attr("class", "fa fa-times"); + } + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + $('#testSendMassEmailSpinner').attr("class", "fa fa-times"); + } + }); + }); + + $('#testSendMassEmailBtn').click(function (e) { + e.preventDefault(); + var base = '@Html.GetBaseUrl()'; + var url = createBaseUrl(base, '/admin/testmassadminemail'); + $('#testSendMassEmailSpinner').attr("class", "fa fa-spinner fa-spin"); + var data = { "Users": "", "Body": $("#massEmailBody").val(), "Subject": $("#massEmailSubject").val() }; + $.ajax({ + type: "post", + url: url, + data: data, + dataType: "json", + success: function (response) { + if (response.result) { + generateNotify(response.message, "success"); + $('#testSendMassEmailSpinner').attr("class", "fa fa-check"); + } else { + + generateNotify(response.message, "danger"); + $('#testSendMassEmailSpinner').attr("class", "fa fa-times"); + } + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + $('#testSendMassEmailSpinner').attr("class", "fa fa-times"); + } + }); + }); + $('#sendMassEmailBtn').click(function (e) { + e.preventDefault(); + var base = '@Html.GetBaseUrl()'; + var url = createBaseUrl(base, '/admin/sendmassemail'); + $('#sendMassEmailSpinner').attr("class", "fa fa-spinner fa-spin"); + var data = { "Users": "", "Body": $("#massEmailBody").val(), "Subject": $("#massEmailSubject").val() }; + $.ajax({ + type: "post", + url: url, + data: data, + dataType: "json", + success: function (response) { + if (response.result) { + generateNotify(response.message, "success"); + $('#sendMassEmailSpinner').attr("class", "fa fa-check"); } else { generateNotify(response.message, "danger"); - $('#spinner').attr("class", "fa fa-times"); + $('#sendMassEmailSpinner').attr("class", "fa fa-times"); } }, error: function (e) { console.log(e); generateNotify("Something went wrong!", "danger"); - $('#spinner').attr("class", "fa fa-times"); + $('#sendMassEmailSpinner').attr("class", "fa fa-times"); } }); }); diff --git a/Ombi.UI/Views/Customization/Customization.cshtml b/Ombi.UI/Views/Customization/Customization.cshtml index 583dbabae..083cc63c7 100644 --- a/Ombi.UI/Views/Customization/Customization.cshtml +++ b/Ombi.UI/Views/Customization/Customization.cshtml @@ -34,7 +34,7 @@
    @@ -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")
    diff --git a/Ombi.UI/Views/Integration/Radarr.cshtml b/Ombi.UI/Views/Integration/Radarr.cshtml index 3d4520e68..1ccccc40f 100644 --- a/Ombi.UI/Views/Integration/Radarr.cshtml +++ b/Ombi.UI/Views/Integration/Radarr.cshtml @@ -64,10 +64,10 @@
    - +
    - - + +
    @@ -241,4 +241,4 @@ }) - \ No newline at end of file + diff --git a/Ombi.UI/Views/Landing/Index.cshtml b/Ombi.UI/Views/Landing/Index.cshtml index 21feaf7eb..b5710224f 100644 --- a/Ombi.UI/Views/Landing/Index.cshtml +++ b/Ombi.UI/Views/Landing/Index.cshtml @@ -33,7 +33,7 @@

    Checking...

    - The Plex server is Loading... (check this page for continuous status updates) + The Media server is Loading... (check this page for continuous status updates)
    diff --git a/Ombi.UI/Views/Requests/Index.cshtml b/Ombi.UI/Views/Requests/Index.cshtml index 7199253c7..867e2c3dc 100644 --- a/Ombi.UI/Views/Requests/Index.cshtml +++ b/Ombi.UI/Views/Requests/Index.cshtml @@ -191,18 +191,36 @@
    - {{#if_eq type "tv"}} - @UI.Search_TV_Show_Status: - {{else}} - @UI.Search_Movie_Status: - {{/if_eq}} - {{status}} - {{#if denied}}
    - Denied: + {{#if_eq type "tv"}} + @UI.Search_TV_Show_Status: + {{else}} + @UI.Search_Movie_Status: + {{/if_eq}} + {{status}} +
    + +
    + Request status: + {{#if available}} + @UI.Search_Available_on_plex + {{else}} + {{#if approved}} + @UI.Search_Processing_Request + {{else if denied}} + @UI.Search_Request_denied {{#if deniedReason}} {{/if}} + {{else}} + @UI.Search_Pending_approval + {{/if}} + {{/if}} +
    + {{#if denied}} +
    + Denied: +
    {{/if}} @@ -211,26 +229,7 @@ {{else}}
    @UI.Requests_ReleaseDate: {{releaseDate}}
    {{/if_eq}} - {{#unless denied}} -
    - @UI.Common_Approved: - {{#if_eq approved false}} - - {{/if_eq}} - {{#if_eq approved true}} - - {{/if_eq}} -
    - {{/unless}} -
    - @UI.Requests_Available - {{#if_eq available false}} - - {{/if_eq}} - {{#if_eq available true}} - - {{/if_eq}} -
    +
    {{#if_eq type "tv"}} {{#if episodes}} diff --git a/Ombi.UI/Views/Search/Index.cshtml b/Ombi.UI/Views/Search/Index.cshtml index cef2e73e8..5e3d9a30a 100644 --- a/Ombi.UI/Views/Search/Index.cshtml +++ b/Ombi.UI/Views/Search/Index.cshtml @@ -8,12 +8,14 @@ { url = "/" + baseUrl.ToHtmlString(); } + + }

    @UI.Search_Title

    -

    @UI.Search_Paragraph

    +

    @string.Format(UI.Search_Paragraph, Model.Emby ? "Emby" : "Plex")


    @@ -583,3 +585,4 @@ @Html.LoadSearchAssets() + diff --git a/Ombi.UI/Views/SystemStatus/Status.cshtml b/Ombi.UI/Views/SystemStatus/Status.cshtml index 8be76882a..71c960a6a 100644 --- a/Ombi.UI/Views/SystemStatus/Status.cshtml +++ b/Ombi.UI/Views/SystemStatus/Status.cshtml @@ -50,9 +50,9 @@ {
    - + @**@
    - + @**@ } else { diff --git a/Ombi.UI/Views/UserLogin/Username.cshtml b/Ombi.UI/Views/UserLogin/Username.cshtml index fcf46d8e7..a62f456ee 100644 --- a/Ombi.UI/Views/UserLogin/Username.cshtml +++ b/Ombi.UI/Views/UserLogin/Username.cshtml @@ -6,7 +6,7 @@

    @UI.UserLogin_Title

    - @UI.UserLogin_Paragraph + @string.Format(UI.UserLogin_Paragraph, Html.GetMediaServerName().ToHtmlString()).ToString()

    diff --git a/Ombi.UI/Views/UserManagementSettings/UserManagementSettings.cshtml b/Ombi.UI/Views/UserManagementSettings/UserManagementSettings.cshtml index db0fae5f2..03164a4ef 100644 --- a/Ombi.UI/Views/UserManagementSettings/UserManagementSettings.cshtml +++ b/Ombi.UI/Views/UserManagementSettings/UserManagementSettings.cshtml @@ -9,7 +9,7 @@ Here you can manage the default permissions and features that your users get - Note: This will not update your users that are currently there, this is to set the default settings to any users added outside of Ombi e.g. You share your Plex Server with a new user, they will be added into Ombi + Note: This will not update your users that are currently there, this is to set the default settings to any users added outside of Ombi e.g. You share your Server with a new user, they will be added into Ombi automatically and will take the permissions and features you have selected below. diff --git a/Ombi.UI/Views/UserWizard/Index.cshtml b/Ombi.UI/Views/UserWizard/Index.cshtml index b8bae77d2..8ecf52d29 100644 --- a/Ombi.UI/Views/UserWizard/Index.cshtml +++ b/Ombi.UI/Views/UserWizard/Index.cshtml @@ -192,7 +192,7 @@
    - +


    -

    Here is a list of Movies and TV Shows that have recently been added to Plex!

    +

    Here is a list of Movies and TV Shows that have recently been added!