diff --git a/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs b/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs index 5d17f771d..c7e570399 100644 --- a/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs +++ b/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs @@ -38,6 +38,6 @@ namespace PlexRequests.Api.Interfaces CouchPotatoProfiles GetProfiles(Uri url, string apiKey); CouchPotatoMovies GetMovies(Uri baseUrl, string apiKey, string[] status); - CoucPotatoApiKey GetApiKey(Uri baseUrl, string username, string password); + CouchPotatoApiKey GetApiKey(Uri baseUrl, string username, string password); } } \ No newline at end of file diff --git a/PlexRequests.Api.Interfaces/IPlexApi.cs b/PlexRequests.Api.Interfaces/IPlexApi.cs index 7bd6c8095..cb2a52049 100644 --- a/PlexRequests.Api.Interfaces/IPlexApi.cs +++ b/PlexRequests.Api.Interfaces/IPlexApi.cs @@ -44,5 +44,6 @@ namespace PlexRequests.Api.Interfaces PlexSearch GetAllEpisodes(string authToken, Uri host, string section, int startPage, int returnCount); PlexServer GetServer(string authToken); PlexSeasonMetadata GetSeasons(string authToken, Uri plexFullHost, string ratingKey); + RecentlyAdded RecentlyAdded(string authToken, Uri plexFullHost); } } \ No newline at end of file diff --git a/PlexRequests.Api.Interfaces/ISonarrApi.cs b/PlexRequests.Api.Interfaces/ISonarrApi.cs index 5c5594ad8..da16e8344 100644 --- a/PlexRequests.Api.Interfaces/ISonarrApi.cs +++ b/PlexRequests.Api.Interfaces/ISonarrApi.cs @@ -46,7 +46,10 @@ namespace PlexRequests.Api.Interfaces IEnumerable GetEpisodes(string seriesId, string apiKey, Uri baseUrl); SonarrEpisode GetEpisode(string episodeId, string apiKey, Uri baseUrl); SonarrEpisode UpdateEpisode(SonarrEpisode episodeInfo, string apiKey, Uri baseUrl); + SonarrEpisodes UpdateEpisode(SonarrEpisodes episodeInfo, string apiKey, Uri baseUrl); SonarrAddEpisodeResult SearchForEpisodes(int[] episodeIds, string apiKey, Uri baseUrl); Series UpdateSeries(Series series, string apiKey, Uri baseUrl); + SonarrSeasonSearchResult SearchForSeason(int seriesId, int seasonNumber, string apiKey, Uri baseUrl); + SonarrSeriesSearchResult SearchForSeries(int seriesId, string apiKey, Uri baseUrl); } } \ No newline at end of file diff --git a/PlexRequests.Api.Models/Movie/CoucPotatoApiKey.cs b/PlexRequests.Api.Models/Movie/CouchPotatoApiKey.cs similarity index 93% rename from PlexRequests.Api.Models/Movie/CoucPotatoApiKey.cs rename to PlexRequests.Api.Models/Movie/CouchPotatoApiKey.cs index 369d438c3..54305fda6 100644 --- a/PlexRequests.Api.Models/Movie/CoucPotatoApiKey.cs +++ b/PlexRequests.Api.Models/Movie/CouchPotatoApiKey.cs @@ -1,7 +1,7 @@ #region Copyright // /************************************************************************ // Copyright (c) 2016 Jamie Rees -// File: CoucPotatoApiKey.cs +// File: CouchPotatoApiKey.cs // Created By: Jamie Rees // // Permission is hereby granted, free of charge, to any person obtaining @@ -28,10 +28,10 @@ using Newtonsoft.Json; namespace PlexRequests.Api.Models.Movie { - public class CoucPotatoApiKey + public class CouchPotatoApiKey { [JsonProperty("success")] - public bool Result { get; set; } + public bool success { get; set; } [JsonProperty("api_key")] public string ApiKey { get; set; } } diff --git a/PlexRequests.Api.Models/Plex/RecentlyAdded.cs b/PlexRequests.Api.Models/Plex/RecentlyAdded.cs new file mode 100644 index 000000000..b5536625a --- /dev/null +++ b/PlexRequests.Api.Models/Plex/RecentlyAdded.cs @@ -0,0 +1,84 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: RecentlyAdded.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.Collections.Generic; + +namespace PlexRequests.Api.Models.Plex +{ + public class RecentlyAddedChild + { + public string _elementType { get; set; } + public string allowSync { get; set; } + public string librarySectionID { get; set; } + public string librarySectionTitle { get; set; } + public string librarySectionUUID { get; set; } + public int ratingKey { get; set; } + public string key { get; set; } + public int parentRatingKey { get; set; } + public string type { get; set; } + public string title { get; set; } + public string parentKey { get; set; } + public string parentTitle { get; set; } + public string parentSummary { get; set; } + public string summary { get; set; } + public int index { get; set; } + public int parentIndex { get; set; } + public string thumb { get; set; } + public string art { get; set; } + public string parentThumb { get; set; } + public int leafCount { get; set; } + public int viewedLeafCount { get; set; } + public int addedAt { get; set; } + public int updatedAt { get; set; } + public List _children { get; set; } + public string studio { get; set; } + public string contentRating { get; set; } + public string rating { get; set; } + public int? viewCount { get; set; } + public int? lastViewedAt { get; set; } + public int? year { get; set; } + public int? duration { get; set; } + public string originallyAvailableAt { get; set; } + public string chapterSource { get; set; } + public string parentTheme { get; set; } + public string titleSort { get; set; } + public string tagline { get; set; } + public int? viewOffset { get; set; } + public string originalTitle { get; set; } + } + + public class RecentlyAdded + { + public string _elementType { get; set; } + public string allowSync { get; set; } + public string identifier { get; set; } + public string mediaTagPrefix { get; set; } + public string mediaTagVersion { get; set; } + public string mixedParents { get; set; } + public List _children { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj index 20363d996..2694cb2bf 100644 --- a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj +++ b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj @@ -49,7 +49,7 @@ - + @@ -73,6 +73,7 @@ + @@ -89,6 +90,9 @@ + + + diff --git a/PlexRequests.Api.Models/Sonarr/SonarrAddEpisodeBody.cs b/PlexRequests.Api.Models/Sonarr/SonarrAddEpisodeBody.cs index 265d881d1..6cf970241 100644 --- a/PlexRequests.Api.Models/Sonarr/SonarrAddEpisodeBody.cs +++ b/PlexRequests.Api.Models/Sonarr/SonarrAddEpisodeBody.cs @@ -29,6 +29,6 @@ namespace PlexRequests.Api.Models.Sonarr public class SonarrAddEpisodeBody { public string name { get; set; } - public int[] episodeIds { get; set; } + public int[] episodeIds { get; set; } } } \ No newline at end of file diff --git a/PlexRequests.Api.Models/Sonarr/SonarrSearchCommand.cs b/PlexRequests.Api.Models/Sonarr/SonarrSearchCommand.cs new file mode 100644 index 000000000..f2649cd94 --- /dev/null +++ b/PlexRequests.Api.Models/Sonarr/SonarrSearchCommand.cs @@ -0,0 +1,38 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrSearchCommand.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.Xml.Linq; + +namespace PlexRequests.Api.Models.Sonarr +{ + public class SonarrSearchCommand + { + public int seriesId { get; set; } + public int seasonNumber { get; set; } + public string name { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Api.Models/Sonarr/SonarrSeasonSearchResult.cs b/PlexRequests.Api.Models/Sonarr/SonarrSeasonSearchResult.cs new file mode 100644 index 000000000..a0fe8bb29 --- /dev/null +++ b/PlexRequests.Api.Models/Sonarr/SonarrSeasonSearchResult.cs @@ -0,0 +1,55 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrSeasonSearchResult.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 PlexRequests.Api.Models.Sonarr +{ + public class SeasonBody + { + public int seriesId { get; set; } + public int seasonNumber { get; set; } + public bool sendUpdatesToClient { get; set; } + public bool updateScheduledTask { get; set; } + public string completionMessage { get; set; } + public string name { get; set; } + public string trigger { get; set; } + } + + public class SonarrSeasonSearchResult + { + public string name { get; set; } + public SeasonBody body { get; set; } + public string priority { get; set; } + public string status { get; set; } + public string queued { get; set; } + public string trigger { get; set; } + public string state { get; set; } + public bool manual { get; set; } + public string startedOn { get; set; } + public bool sendUpdatesToClient { get; set; } + public bool updateScheduledTask { get; set; } + public int id { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Api.Models/Sonarr/SonarrSeriesSearchResult.cs b/PlexRequests.Api.Models/Sonarr/SonarrSeriesSearchResult.cs new file mode 100644 index 000000000..76e5fc9ad --- /dev/null +++ b/PlexRequests.Api.Models/Sonarr/SonarrSeriesSearchResult.cs @@ -0,0 +1,56 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrSeriesSearchResult.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 PlexRequests.Api.Models.Sonarr +{ + public class SeriesBody + { + public int seriesId { get; set; } + public bool sendUpdatesToClient { get; set; } + public bool updateScheduledTask { get; set; } + public string completionMessage { get; set; } + public string name { get; set; } + public string trigger { get; set; } + } + + public class SonarrSeriesSearchResult + { + public string name { get; set; } + public SeriesBody body { get; set; } + public string priority { get; set; } + public string status { get; set; } + public string queued { get; set; } + public string started { get; set; } + public string trigger { get; set; } + public string state { get; set; } + public bool manual { get; set; } + public string startedOn { get; set; } + public string stateChangeTime { get; set; } + public bool sendUpdatesToClient { get; set; } + public bool updateScheduledTask { get; set; } + public int id { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Api/CouchPotatoApi.cs b/PlexRequests.Api/CouchPotatoApi.cs index f9f886fbb..e4382ff22 100644 --- a/PlexRequests.Api/CouchPotatoApi.cs +++ b/PlexRequests.Api/CouchPotatoApi.cs @@ -160,18 +160,18 @@ namespace PlexRequests.Api } } - public CoucPotatoApiKey GetApiKey(Uri baseUrl, string username, string password) + public CouchPotatoApiKey GetApiKey(Uri baseUrl, string username, string password) { var request = new RestRequest { - Resource = "getkey/?p={username}&u={password}", + Resource = "getkey/?u={username}&p={password}", Method = Method.GET }; request.AddUrlSegment("username", StringHasher.CalcuateMd5Hash(username)); request.AddUrlSegment("password", StringHasher.CalcuateMd5Hash(password)); - var obj = RetryHandler.Execute(() => Api.Execute(request, baseUrl), + var obj = RetryHandler.Execute(() => Api.Execute(request, baseUrl), (exception, timespan) => Log.Error(exception, "Exception when calling GetApiKey for CP, Retrying {0}", timespan), null); return obj; diff --git a/PlexRequests.Api/PlexApi.cs b/PlexRequests.Api/PlexApi.cs index 233bb66ff..83e06d7cd 100644 --- a/PlexRequests.Api/PlexApi.cs +++ b/PlexRequests.Api/PlexApi.cs @@ -347,6 +347,39 @@ namespace PlexRequests.Api return servers; } + public RecentlyAdded RecentlyAdded(string authToken, Uri plexFullHost) + { + var request = new RestRequest + { + Method = Method.GET, + Resource = "library/recentlyAdded" + }; + + request.AddHeader("X-Plex-Token", authToken); + request.AddHeader("X-Plex-Client-Identifier", $"PlexRequests.Net{Version}"); + request.AddHeader("X-Plex-Product", "Plex Requests .Net"); + request.AddHeader("X-Plex-Version", Version); + request.AddHeader("Content-Type", "application/json"); + request.AddHeader("Accept", "application/json"); + + try + { + var lib = RetryHandler.Execute(() => Api.ExecuteJson(request, plexFullHost), + (exception, timespan) => Log.Error(exception, "Exception when calling RecentlyAdded for Plex, Retrying {0}", timespan), new[] { + TimeSpan.FromSeconds (5), + TimeSpan.FromSeconds(10), + TimeSpan.FromSeconds(30) + }); + + return lib; + } + catch (Exception e) + { + Log.Error(e, "There has been a API Exception when attempting to get the Plex RecentlyAdded"); + return new RecentlyAdded(); + } + } + private void AddHeaders(ref RestRequest request, string authToken) { request.AddHeader("X-Plex-Token", authToken); diff --git a/PlexRequests.Api/SonarrApi.cs b/PlexRequests.Api/SonarrApi.cs index 6cc8019f3..e90c061cd 100644 --- a/PlexRequests.Api/SonarrApi.cs +++ b/PlexRequests.Api/SonarrApi.cs @@ -273,6 +273,25 @@ namespace PlexRequests.Api } } + public SonarrEpisodes UpdateEpisode(SonarrEpisodes episodeInfo, string apiKey, Uri baseUrl) + { + var request = new RestRequest { Resource = "/api/Episode", Method = Method.PUT }; + request.AddHeader("X-Api-Key", apiKey); + request.AddJsonBody(episodeInfo); + try + { + var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => + Log.Error(exception, "Exception when calling UpdateEpisode for Sonarr, Retrying {0}", timespan)); + + return policy.Execute(() => Api.ExecuteJson(request, baseUrl)); + } + catch (Exception e) + { + Log.Error(e, "There has been an API exception when put the Sonarr UpdateEpisode"); + return null; + } + } + /// /// Search for one or more episodes /// @@ -327,5 +346,58 @@ namespace PlexRequests.Api return null; } } + + public SonarrSeasonSearchResult SearchForSeason(int seriesId, int seasonNumber, string apiKey, Uri baseUrl) + { + var request = new RestRequest { Resource = "/api/Command", Method = Method.POST }; + request.AddHeader("X-Api-Key", apiKey); + + var body = new SonarrSearchCommand + { + name = "SeasonSearch", + seriesId = seriesId, + seasonNumber = seasonNumber + }; + request.AddJsonBody(body); + + try + { + var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => + Log.Error(exception, "Exception when calling SearchForSeason for Sonarr, Retrying {0}", timespan)); + + return policy.Execute(() => Api.ExecuteJson(request, baseUrl)); + } + catch (Exception e) + { + Log.Error(e, "There has been an API exception when put the Sonarr SearchForSeason"); + return null; + } + } + + public SonarrSeriesSearchResult SearchForSeries(int seriesId, string apiKey, Uri baseUrl) + { + var request = new RestRequest { Resource = "/api/Command", Method = Method.POST }; + request.AddHeader("X-Api-Key", apiKey); + + var body = new SonarrSearchCommand + { + name = "SeriesSearch", + seriesId = seriesId + }; + request.AddJsonBody(body); + + try + { + var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => + Log.Error(exception, "Exception when calling SearchForSeries for Sonarr, Retrying {0}", timespan)); + + return policy.Execute(() => Api.ExecuteJson(request, baseUrl)); + } + catch (Exception e) + { + Log.Error(e, "There has been an API exception when put the Sonarr SearchForSeries"); + return null; + } + } } } \ No newline at end of file diff --git a/PlexRequests.Api/TheMovieDbApi.cs b/PlexRequests.Api/TheMovieDbApi.cs index 8137ad05f..0e860d58a 100644 --- a/PlexRequests.Api/TheMovieDbApi.cs +++ b/PlexRequests.Api/TheMovieDbApi.cs @@ -74,6 +74,12 @@ namespace PlexRequests.Api return movies; } + public async Task GetMovieInformation(string imdbId) + { + var movies = await Client.GetMovie(imdbId); + return movies; + } + [Obsolete("Should use TvMaze for TV")] public async Task GetTvShowInformation(int tmdbId) { diff --git a/PlexRequests.Core.Tests/NotificationMessageResolverTests.cs b/PlexRequests.Core.Tests/NotificationMessageResolverTests.cs index 58cfb06e5..8b89a6e2f 100644 --- a/PlexRequests.Core.Tests/NotificationMessageResolverTests.cs +++ b/PlexRequests.Core.Tests/NotificationMessageResolverTests.cs @@ -1,147 +1,147 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: AuthenticationSettingsTests.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; +//#region Copyright +//// /************************************************************************ +//// Copyright (c) 2016 Jamie Rees +//// File: AuthenticationSettingsTests.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 NUnit.Framework; +//using NUnit.Framework; -using PlexRequests.Core.Models; -using PlexRequests.Core.Notification; -using PlexRequests.Core.SettingModels; +//using PlexRequests.Core.Models; +//using PlexRequests.Core.Notification; +//using PlexRequests.Core.SettingModels; -namespace PlexRequests.Core.Tests -{ - [TestFixture] - public class NotificationMessageResolverTests - { - [TestCaseSource(nameof(MessageBodyResolver))] - public string ResolveBody(string body, NotificationMessageCurlys param) - { - var n = new NotificationMessageResolver(); - var s = new NotificationSettings - { - Message = new List { new Notification.NotificationMessage { NotificationType = NotificationType.NewRequest, Body = body } } - }; +//namespace PlexRequests.Core.Tests +//{ +// [TestFixture] +// public class NotificationMessageResolverTests +// { +// [TestCaseSource(nameof(MessageBodyResolver))] +// public string ResolveBody(string body, NotificationMessageCurlys param) +// { +// var n = new NotificationMessageResolver(); +// var s = new NotificationSettings +// { +// Message = new List { new Notification.NotificationMessage { NotificationType = NotificationType.NewRequest, Body = body } } +// }; - var result = n.ParseMessage(s, NotificationType.NewRequest, param); - return result.Body; - } +// var result = n.ParseMessage(s, NotificationType.NewRequest, param, TransportType.Email); +// return result.Body; +// } - [TestCaseSource(nameof(MessageSubjectResolver))] - public string ResolveSubject(string subject, NotificationMessageCurlys param) - { - var n = new NotificationMessageResolver(); - var s = new NotificationSettings - { - Message = new List { new Notification.NotificationMessage { NotificationType = NotificationType.NewRequest, Subject = subject }} - }; +// [TestCaseSource(nameof(MessageSubjectResolver))] +// public string ResolveSubject(string subject, NotificationMessageCurlys param) +// { +// var n = new NotificationMessageResolver(); +// var s = new NotificationSettings +// { +// Message = new List { new Notification.NotificationMessage { NotificationType = NotificationType.NewRequest, Subject = subject }} +// }; - var result = n.ParseMessage(s, NotificationType.NewRequest, param); - return result.Subject; - } +// var result = n.ParseMessage(s, NotificationType.NewRequest, param, TransportType.Email); +// return result.Subject; +// } - private static IEnumerable MessageSubjectResolver - { - get - { - yield return new TestCaseData( - "{Username} has requested a {Type}", - new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) - .Returns("Jamie has requested a Movie").SetName("Subject Curlys"); +// private static IEnumerable MessageSubjectResolver +// { +// get +// { +// yield return new TestCaseData( +// "{Username} has requested a {Type}", +// new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) +// .Returns("Jamie has requested a Movie").SetName("Subject Curlys"); - yield return new TestCaseData( - null, - new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) - .Returns(string.Empty).SetName("Empty Subject"); +// yield return new TestCaseData( +// null, +// new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) +// .Returns(string.Empty).SetName("Empty Subject"); - yield return new TestCaseData( - "New Request Incoming!", - new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) - .Returns("New Request Incoming!").SetName("No curlys"); +// yield return new TestCaseData( +// "New Request Incoming!", +// new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) +// .Returns("New Request Incoming!").SetName("No curlys"); - yield return new TestCaseData( - "%$R£%$£^%$&{Username}@{}:§", - new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) - .Returns("%$R£%$£^%$&Jamie@{}:§").SetName("Special Chars"); - } - } - private static IEnumerable MessageBodyResolver - { - get - { - yield return new TestCaseData( - "There has been a new request from {Username}, Title: {Title} for {Type}", - new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) - .Returns("There has been a new request from Jamie, Title: Finding Dory for Movie").SetName("FindingDory"); +// yield return new TestCaseData( +// "%$R£%$£^%$&{Username}@{}:§", +// new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) +// .Returns("%$R£%$£^%$&Jamie@{}:§").SetName("Special Chars"); +// } +// } +// private static IEnumerable MessageBodyResolver +// { +// get +// { +// yield return new TestCaseData( +// "There has been a new request from {Username}, Title: {Title} for {Type}", +// new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) +// .Returns("There has been a new request from Jamie, Title: Finding Dory for Movie").SetName("FindingDory"); - yield return new TestCaseData( - null, - new NotificationMessageCurlys(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)) - .Returns(string.Empty) - .SetName("Empty Message"); +// yield return new TestCaseData( +// null, +// new NotificationMessageCurlys(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)) +// .Returns(string.Empty) +// .SetName("Empty Message"); - yield return new TestCaseData( - "{{Wowwzer}} Damn}{{Username}}}}", - new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, string.Empty)) - .Returns("{{Wowwzer}} Damn}{HEY!}}}") - .SetName("Multiple Curlys"); +// yield return new TestCaseData( +// "{{Wowwzer}} Damn}{{Username}}}}", +// new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, string.Empty)) +// .Returns("{{Wowwzer}} Damn}{HEY!}}}") +// .SetName("Multiple Curlys"); - yield return new TestCaseData( - "This is a message with no curlys", - new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) - .Returns("This is a message with no curlys") - .SetName("No Curlys"); +// yield return new TestCaseData( +// "This is a message with no curlys", +// new NotificationMessageCurlys("Jamie", "Finding Dory", DateTime.Now.ToString(), "Movie", string.Empty)) +// .Returns("This is a message with no curlys") +// .SetName("No Curlys"); - yield return new TestCaseData( - new string(')', 5000), - new NotificationMessageCurlys(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)) - .Returns(new string(')', 5000)) - .SetName("Long String"); +// yield return new TestCaseData( +// new string(')', 5000), +// new NotificationMessageCurlys(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty)) +// .Returns(new string(')', 5000)) +// .SetName("Long String"); - yield return new TestCaseData( - "This is a {Username} and {Username} Because {Issue}{Issue}", - new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, "Bob")) - .Returns("This is a HEY! and HEY! Because BobBob") - .SetName("Double Curly"); +// yield return new TestCaseData( +// "This is a {Username} and {Username} Because {Issue}{Issue}", +// new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, "Bob")) +// .Returns("This is a HEY! and HEY! Because BobBob") +// .SetName("Double Curly"); - yield return new TestCaseData( - "This is a {username} and {username} Because {Issue}{Issue}", - new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, "Bob")) - .Returns("This is a {username} and {username} Because BobBob") - .SetName("Case sensitive"); +// yield return new TestCaseData( +// "This is a {username} and {username} Because {Issue}{Issue}", +// new NotificationMessageCurlys("HEY!", string.Empty, string.Empty, string.Empty, "Bob")) +// .Returns("This is a {username} and {username} Because BobBob") +// .SetName("Case sensitive"); - yield return new TestCaseData( - "{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}", - new NotificationMessageCurlys("HEY!", string.Empty, "b", string.Empty, "Bob")) - .Returns("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") - .SetName("Lots of curlys"); - } - } - } -} \ No newline at end of file +// yield return new TestCaseData( +// "{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}{Date}", +// new NotificationMessageCurlys("HEY!", string.Empty, "b", string.Empty, "Bob")) +// .Returns("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") +// .SetName("Lots of curlys"); +// } +// } +// } +//} \ No newline at end of file diff --git a/PlexRequests.Core/Notification/NotificationMessageResolver.cs b/PlexRequests.Core/Notification/NotificationMessageResolver.cs index ed90bbf12..f9c7b1b82 100644 --- a/PlexRequests.Core/Notification/NotificationMessageResolver.cs +++ b/PlexRequests.Core/Notification/NotificationMessageResolver.cs @@ -24,6 +24,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion + +using System; using System.Collections.Generic; using System.Linq; @@ -50,16 +52,37 @@ namespace PlexRequests.Core.Notification /// The notification. /// The type. /// The c. + /// Type of the transport. /// - public NotificationMessageContent ParseMessage(T notification, NotificationType type, NotificationMessageCurlys c) where T : NotificationSettings + public NotificationMessageContent ParseMessage(NotificationSettingsV2 notification, NotificationType type, NotificationMessageCurlys c, TransportType transportType) { - var content = notification.Message.FirstOrDefault(x => x.NotificationType == type); + IEnumerable content = null; + switch (transportType) + { + case TransportType.Email: + content = notification.EmailNotification; + break; + case TransportType.Pushbullet: + content = notification.PushbulletNotification; + break; + case TransportType.Pushover: + content = notification.PushoverNotification; + break; + case TransportType.Slack: + content = notification.SlackNotification; + break; + default: + throw new ArgumentOutOfRangeException(nameof(transportType), transportType, null); + } + if (content == null) { return new NotificationMessageContent(); } - return Resolve(content.Body, content.Subject, c.Curlys); + var message = content.FirstOrDefault(x => x.NotificationType == type) ?? new NotificationMessage(); + + return Resolve(message.Body, message.Subject, c.Curlys); } /// @@ -78,7 +101,7 @@ namespace PlexRequests.Core.Notification body = ReplaceFields(bodyFields, parameters, body); subject = ReplaceFields(subjectFields, parameters, subject); - return new NotificationMessageContent { Body = body ?? string.Empty, Subject = subject ?? string.Empty }; + return new NotificationMessageContent {Body = body ?? string.Empty, Subject = subject ?? string.Empty}; } /// @@ -123,7 +146,6 @@ namespace PlexRequests.Core.Notification { currentWord += c.ToString(); // Add the character onto the word. } - } return fields; diff --git a/PlexRequests.Core/Notification/Templates/BasicRequestTemplate.html b/PlexRequests.Core/Notification/Templates/BasicRequestTemplate.html new file mode 100644 index 000000000..3d005619e --- /dev/null +++ b/PlexRequests.Core/Notification/Templates/BasicRequestTemplate.html @@ -0,0 +1,189 @@ + + + + + + Plex Requests .Net + + + + + + + + + +
  +
+ + + + + + + + + + + +
+ + + + + + + + + + +
+ +
+

Hi there!

+

{@SUBJECT}

+

{@BODY}

+ +
+ +
+
+ + + + + + +
+
 
+ + \ No newline at end of file diff --git a/PlexRequests.Core/Notification/Templates/EmailBasicTemplate.cs b/PlexRequests.Core/Notification/Templates/EmailBasicTemplate.cs new file mode 100644 index 000000000..8ce53afb6 --- /dev/null +++ b/PlexRequests.Core/Notification/Templates/EmailBasicTemplate.cs @@ -0,0 +1,70 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: EmailBasicTemplate.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.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using NLog; +using PlexRequests.Core.Models; +using PlexRequests.Core.SettingModels; + +namespace PlexRequests.Core.Notification.Templates +{ + public class EmailBasicTemplate : IEmailBasicTemplate + { + public string TemplateLocation => Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? string.Empty, "Notification", "Templates", "BasicRequestTemplate.html"); + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); + + private const string SubjectKey = "{@SUBJECT}"; + private const string BodyKey = "{@BODY}"; + private const string ImgSrc = "{@IMGSRC}"; + private const string DateKey = "{@DATENOW}"; + + public string LoadTemplate(string subject, string body, string imgSrc) + { + try + { + var sb = new StringBuilder(File.ReadAllText(TemplateLocation)); + sb.Replace(SubjectKey, subject); + sb.Replace(BodyKey, body); + sb.Replace(ImgSrc, imgSrc); + sb.Replace(DateKey, DateTime.Now.ToString("f")); + + return sb.ToString(); + } + catch (Exception e) + { + Log.Error(e); + return string.Empty; + } + } + } +} \ No newline at end of file diff --git a/PlexRequests.Core/Notification/Templates/IEmailBasicTemplate.cs b/PlexRequests.Core/Notification/Templates/IEmailBasicTemplate.cs new file mode 100644 index 000000000..e72645722 --- /dev/null +++ b/PlexRequests.Core/Notification/Templates/IEmailBasicTemplate.cs @@ -0,0 +1,37 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: IEmailBasicTemplate.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.Threading.Tasks; + +namespace PlexRequests.Core.Notification.Templates +{ + public interface IEmailBasicTemplate + { + string LoadTemplate(string subject, string body, string imgSrc); + string TemplateLocation { get; } + } +} \ No newline at end of file diff --git a/PlexRequests.Core/Notification/TransportType.cs b/PlexRequests.Core/Notification/TransportType.cs new file mode 100644 index 000000000..6244b2f99 --- /dev/null +++ b/PlexRequests.Core/Notification/TransportType.cs @@ -0,0 +1,36 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: TransportType.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 PlexRequests.Core.Notification +{ + public enum TransportType + { + Email, + Pushbullet, + Pushover, + Slack + } +} \ No newline at end of file diff --git a/PlexRequests.Core/PlexRequests.Core.csproj b/PlexRequests.Core/PlexRequests.Core.csproj index 2e2d1b3a1..d3cd82a7b 100644 --- a/PlexRequests.Core/PlexRequests.Core.csproj +++ b/PlexRequests.Core/PlexRequests.Core.csproj @@ -44,6 +44,7 @@ + @@ -81,11 +82,15 @@ + + + + @@ -134,7 +139,11 @@ PlexRequests.Store - + + + PreserveNewest + + + + + + + + + + + +
+ + + + + + + +
+ +
+
+
+

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

+ +
+ + {@RECENTLYADDED} + +
+ + + + + + + + +   + + + + \ No newline at end of file diff --git a/PlexRequests.Services/Models/SonarrCachedResult.cs b/PlexRequests.Services/Models/SonarrCachedResult.cs new file mode 100644 index 000000000..1398a7ce4 --- /dev/null +++ b/PlexRequests.Services/Models/SonarrCachedResult.cs @@ -0,0 +1,47 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrCachedResult.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.Collections.Generic; + +namespace PlexRequests.Services.Models +{ + public class SonarrCachedResult + { + public SonarrCachedResult() + { + Seasons = new List( ); + } + public List Seasons { get; set; } + public int TvdbId { get; set; } + } + + public class SonarrSeasons + { + public int SeasonNumber { get; set; } + public bool Monitored { get; set; } + } +} \ No newline at end of file diff --git a/PlexRequests.Services/Notification/EmailMessageNotification.cs b/PlexRequests.Services/Notification/EmailMessageNotification.cs index a81a15290..3f6bf9c91 100644 --- a/PlexRequests.Services/Notification/EmailMessageNotification.cs +++ b/PlexRequests.Services/Notification/EmailMessageNotification.cs @@ -25,18 +25,13 @@ // ************************************************************************/ #endregion using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; using System.Threading.Tasks; - -using MailKit.Security; - using MimeKit; using NLog; using PlexRequests.Core; using PlexRequests.Core.Models; +using PlexRequests.Core.Notification.Templates; using PlexRequests.Core.SettingModels; using PlexRequests.Services.Interfaces; using SmtpClient = MailKit.Net.Smtp.SmtpClient; @@ -109,7 +104,7 @@ namespace PlexRequests.Services.Notification if (string.IsNullOrEmpty(settings.EmailUsername) || string.IsNullOrEmpty(settings.EmailPassword)) { return false; - } + } } if (string.IsNullOrEmpty(settings.EmailHost) || string.IsNullOrEmpty(settings.RecipientEmail) || string.IsNullOrEmpty(settings.EmailPort.ToString())) { @@ -129,13 +124,16 @@ namespace PlexRequests.Services.Notification private async Task EmailNewRequest(NotificationModel model, EmailNotificationSettings settings) { - //var r = new NotificationMessageCurlys(model.User, model.Title, DateTime.Now.ToString(), model.RequestType.ToString(), string.Empty); - //var resolver = new NotificationMessageResolver(); - //var bodyResult = resolver.ParseMessage(settings, NotificationType.NewRequest, r); - + var email = new EmailBasicTemplate(); + var html = email.LoadTemplate( + $"Plex Requests: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!", + $"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}", + model.ImgSrc); + var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." }; + var message = new MimeMessage { - Body = new TextPart("plain") { Text = $"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}" }, + Body = body.ToMessageBody(), Subject = $"Plex Requests: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!" }; message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); @@ -147,9 +145,16 @@ namespace PlexRequests.Services.Notification private async Task EmailIssue(NotificationModel model, EmailNotificationSettings settings) { + var email = new EmailBasicTemplate(); + var html = email.LoadTemplate( + $"Plex Requests: New issue for {model.Title}!", + $"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!", + model.ImgSrc); + var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." }; + var message = new MimeMessage { - Body = new TextPart("plain") { Text = $"Hello! The user '{model.User}' has reported a new issue {model.Body} for the title {model.Title}!" }, + Body = body.ToMessageBody(), Subject = $"Plex Requests: New issue for {model.Title}!" }; message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); @@ -165,10 +170,16 @@ namespace PlexRequests.Services.Notification { await Task.FromResult(false); } + var email = new EmailBasicTemplate(); + var html = email.LoadTemplate( + $"Plex Requests: {model.Title} is now available!", + $"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)", + model.ImgSrc); + var body = new BodyBuilder { HtmlBody = html, TextBody = "This email is only available on devices that support HTML." }; var message = new MimeMessage { - Body = new TextPart("plain") { Text = $"Hello! You requested {model.Title} on PlexRequests! This is now available on Plex! :)" }, + Body = body.ToMessageBody(), Subject = $"Plex Requests: {model.Title} is now available!" }; message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); @@ -206,10 +217,15 @@ namespace PlexRequests.Services.Notification private async Task EmailTest(NotificationModel model, EmailNotificationSettings settings) { + var email = new EmailBasicTemplate(); + var html = email.LoadTemplate( + "Test Message", + "This is just a test! Success!", + model.ImgSrc); + var body = new BodyBuilder { HtmlBody = html, }; var message = new MimeMessage { - Body = new TextPart("plain") { Text = "This is just a test! Success!" }, - Subject = "Plex Requests: Test Message!", + Body = body.ToMessageBody() }; message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); message.To.Add(new MailboxAddress(settings.RecipientEmail, settings.RecipientEmail)); diff --git a/PlexRequests.Services/Notification/NotificationEngine.cs b/PlexRequests.Services/Notification/NotificationEngine.cs index ccbe07fec..50dc4fc49 100644 --- a/PlexRequests.Services/Notification/NotificationEngine.cs +++ b/PlexRequests.Services/Notification/NotificationEngine.cs @@ -75,7 +75,7 @@ namespace PlexRequests.Services.Notification if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase)) { Log.Info("This user is the Plex server owner"); - await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title); + await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath); return; } @@ -88,7 +88,7 @@ namespace PlexRequests.Services.Notification } Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title); - await PublishUserNotification(email.Username, email.Email, model.Title); + await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath); } } } @@ -117,7 +117,7 @@ namespace PlexRequests.Services.Notification if (user.Equals(adminUsername, StringComparison.CurrentCultureIgnoreCase)) { Log.Info("This user is the Plex server owner"); - await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title); + await PublishUserNotification(userAccount.Username, userAccount.Email, model.Title, model.PosterPath); return; } @@ -130,7 +130,7 @@ namespace PlexRequests.Services.Notification } Log.Info("Sending notification to: {0} at: {1}, for title: {2}", email.Username, email.Email, model.Title); - await PublishUserNotification(email.Username, email.Email, model.Title); + await PublishUserNotification(email.Username, email.Email, model.Title, model.PosterPath); } } catch (Exception e) @@ -139,14 +139,15 @@ namespace PlexRequests.Services.Notification } } - private async Task PublishUserNotification(string username, string email, string title) + private async Task PublishUserNotification(string username, string email, string title, string img) { var notificationModel = new NotificationModel { User = username, UserEmail = email, NotificationType = NotificationType.RequestAvailable, - Title = title + Title = title, + ImgSrc = img }; // Send the notification to the user. diff --git a/PlexRequests.Services/Notification/NotificationModel.cs b/PlexRequests.Services/Notification/NotificationModel.cs index 11ebcbae3..4114083bb 100644 --- a/PlexRequests.Services/Notification/NotificationModel.cs +++ b/PlexRequests.Services/Notification/NotificationModel.cs @@ -40,5 +40,6 @@ namespace PlexRequests.Services.Notification public string User { get; set; } public string UserEmail { get; set; } public RequestType RequestType { get; set; } + public string ImgSrc { get; set; } } } \ No newline at end of file diff --git a/PlexRequests.Services/PlexRequests.Services.csproj b/PlexRequests.Services/PlexRequests.Services.csproj index 6aed947bc..6c0f8392b 100644 --- a/PlexRequests.Services/PlexRequests.Services.csproj +++ b/PlexRequests.Services/PlexRequests.Services.csproj @@ -72,19 +72,26 @@ ..\packages\Quartz.2.3.3\lib\net40\Quartz.dll + + False + ..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll +
+ + + @@ -97,6 +104,7 @@ + @@ -136,6 +144,11 @@ PlexRequests.Store + + + PreserveNewest + + +
+
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ } +
+ +
+
+ +
+
+ + + + + + \ No newline at end of file diff --git a/PlexRequests.UI/Views/Admin/SchedulerSettings.cshtml b/PlexRequests.UI/Views/Admin/SchedulerSettings.cshtml index bd629c5d5..4621981e7 100644 --- a/PlexRequests.UI/Views/Admin/SchedulerSettings.cshtml +++ b/PlexRequests.UI/Views/Admin/SchedulerSettings.cshtml @@ -6,15 +6,19 @@
-
Job Name
-
Last Run
+
Job Name +
+
Last Run +
+
@foreach (var record in Model.JobRecorder) {
-
@record.Key
-
@record.Value.ToString("O")
+
@record.Key
+
@record.Value.ToString("O")
+
}

@@ -35,7 +39,7 @@ Please note, the minimum time for this to run is 11 hours, if set below 11 then we will ignore that value. This is a very resource intensive job, the less we run it the better.
- +
@@ -54,27 +58,34 @@
- +
- +
- Please note, this will not reset the users request limit, it will just check every X hours to see if it needs to be reset. + Please note, this will not reset the users request limit, it will just check every @Model.UserRequestLimitResetter hours to see if it needs to be reset.
- +
+
+ +
+ +
+
+
diff --git a/PlexRequests.UI/Views/Admin/Settings.cshtml b/PlexRequests.UI/Views/Admin/Settings.cshtml index 79aa9eb47..386b209c8 100644 --- a/PlexRequests.UI/Views/Admin/Settings.cshtml +++ b/PlexRequests.UI/Views/Admin/Settings.cshtml @@ -65,17 +65,37 @@
-
- -
- -
+
+ +
+
+
+
+
+
+
-
+ Note: This will require you to setup your email notifications + @if (Model.SendRecentlyAddedEmail) + { + + } + else + { + + } + +
+
+ +
+
+ +
@if (Model.SearchForMovies) @@ -193,6 +213,36 @@ }
+ +
+
+ + @if (Model.DisableTvRequestsByEpisode) + { + + + } + else + { + + } +
+
+ +
+
+ + @if (Model.DisableTvRequestsBySeason) + { + + + } + else + { + + } +
+
@@ -325,5 +375,29 @@ } }); }); + + $('#recentlyAddedBtn').click(function (e) { + e.preventDefault(); + var base = '@Html.GetBaseUrl()'; + var url = createBaseUrl(base, '/admin/recentlyAddedTest'); + + $.ajax({ + type: "post", + url: url, + dataType: "json", + success: function (response) { + if (response) { + generateNotify(response.message, "success"); + } else { + + generateNotify(response.message, "danger"); + } + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + } + }); + }); }); \ No newline at end of file diff --git a/PlexRequests.UI/Views/Search/Index.cshtml b/PlexRequests.UI/Views/Search/Index.cshtml index b8e9f3bfc..5d29eb483 100644 --- a/PlexRequests.UI/Views/Search/Index.cshtml +++ b/PlexRequests.UI/Views/Search/Index.cshtml @@ -168,12 +168,15 @@ {{/if_eq}} {{#if_eq type "tv"}} {{#if available}} - Available + Available on Plex {{else}} - Not Available + {{#if approved}} + Processing request + {{else if requested}} + Pending approval + {{else}} + Not Requested yet {{/if}} - {{#if requested}} - Requested {{/if}}

@@ -210,10 +213,14 @@
{{#if available}} diff --git a/PlexRequests.UI/Views/Shared/Partial/_Head.cshtml b/PlexRequests.UI/Views/Shared/Partial/_Head.cshtml index d0de5d0bc..927c6cad7 100644 --- a/PlexRequests.UI/Views/Shared/Partial/_Head.cshtml +++ b/PlexRequests.UI/Views/Shared/Partial/_Head.cshtml @@ -19,6 +19,7 @@ @UI.Layout_Title + @Html.LoadAnalytics() diff --git a/PlexRequests.sln b/PlexRequests.sln index f806ea2f7..ec6287fad 100644 --- a/PlexRequests.sln +++ b/PlexRequests.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI", "PlexRequests.UI\PlexRequests.UI.csproj", "{68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}" EndProject