From e5d7c4c3ec36959ead54e1ec8b77f7eaf4e2ed42 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 17 Jan 2017 21:28:11 +0000 Subject: [PATCH 1/4] Fixed #940 don't show any shows without a tvdb id Added a link to the netflix movie when you click the label --- Ombi.UI/Content/search.js | 2 +- Ombi.UI/Modules/SearchExtensionModule.cs | 2 +- Ombi.UI/Modules/SearchModule.cs | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Ombi.UI/Content/search.js b/Ombi.UI/Content/search.js index 8b71215fb..8b9c10109 100644 --- a/Ombi.UI/Content/search.js +++ b/Ombi.UI/Content/search.js @@ -355,7 +355,7 @@ $(function () { if (results.result) { // It's on Netflix $('#' + id + 'netflixTab') - .html("Avaialble on Netflix"); + .html("Avaialble on Netflix"); } }); diff --git a/Ombi.UI/Modules/SearchExtensionModule.cs b/Ombi.UI/Modules/SearchExtensionModule.cs index 05fdfe003..4c0ee4a6f 100644 --- a/Ombi.UI/Modules/SearchExtensionModule.cs +++ b/Ombi.UI/Modules/SearchExtensionModule.cs @@ -54,7 +54,7 @@ namespace Ombi.UI.Modules return Response.AsJson(new { Result = false }); } - return Response.AsJson(new { Result = true }); + return Response.AsJson(new { Result = true, NetflixId = result.ShowId }); } diff --git a/Ombi.UI/Modules/SearchModule.cs b/Ombi.UI/Modules/SearchModule.cs index 8759d0325..30acdf68a 100644 --- a/Ombi.UI/Modules/SearchModule.cs +++ b/Ombi.UI/Modules/SearchModule.cs @@ -246,6 +246,7 @@ namespace Ombi.UI.Modules if (counter <= 5) // Let's only do it for the first 5 items { var movieInfoTask = await MovieApi.GetMovieInformation(movie.Id).ConfigureAwait(false); + // TODO needs to be careful about this, it's adding extra time to search... // https://www.themoviedb.org/talk/5807f4cdc3a36812160041f2 imdbId = movieInfoTask?.ImdbId; @@ -345,6 +346,10 @@ namespace Ombi.UI.Modules var viewTv = new List(); foreach (var t in apiTv) { + if (!(t.show.externals?.thetvdb.HasValue) ?? false) + { + continue; + } var banner = t.show.image?.medium; if (!string.IsNullOrEmpty(banner)) { From 5e06d9bd2692e82c8d4beea93fa9e6c080273fcc Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 17 Jan 2017 22:28:13 +0000 Subject: [PATCH 2/4] Radarr integartion in progress #923 --- Ombi.Api.Interfaces/IRadarrApi.cs | 15 + .../Ombi.Api.Interfaces.csproj | 1 + Ombi.Api.Models/Ombi.Api.Models.csproj | 4 + Ombi.Api.Models/Radarr/RadarrAddMovie.cs | 50 ++++ Ombi.Api.Models/Radarr/RadarrAddOptions.cs | 35 +++ Ombi.Api.Models/Radarr/RadarrError.cs | 34 +++ Ombi.Api.Models/Radarr/RadarrMovieResponse.cs | 80 ++++++ Ombi.Api/Ombi.Api.csproj | 1 + Ombi.Api/RadarrApi.cs | 152 ++++++++++ Ombi.Core/Ombi.Core.csproj | 1 + Ombi.Core/SettingModels/RadarrSettings.cs | 37 +++ Ombi.UI/Ombi.UI.csproj | 3 + Ombi.UI/Views/Admin/Radarr.cshtml | 260 ++++++++++++++++++ 13 files changed, 673 insertions(+) create mode 100644 Ombi.Api.Interfaces/IRadarrApi.cs create mode 100644 Ombi.Api.Models/Radarr/RadarrAddMovie.cs create mode 100644 Ombi.Api.Models/Radarr/RadarrAddOptions.cs create mode 100644 Ombi.Api.Models/Radarr/RadarrError.cs create mode 100644 Ombi.Api.Models/Radarr/RadarrMovieResponse.cs create mode 100644 Ombi.Api/RadarrApi.cs create mode 100644 Ombi.Core/SettingModels/RadarrSettings.cs create mode 100644 Ombi.UI/Views/Admin/Radarr.cshtml diff --git a/Ombi.Api.Interfaces/IRadarrApi.cs b/Ombi.Api.Interfaces/IRadarrApi.cs new file mode 100644 index 000000000..8d6af90ce --- /dev/null +++ b/Ombi.Api.Interfaces/IRadarrApi.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using Ombi.Api.Models.Radarr; +using Ombi.Api.Models.Sonarr; + +namespace Ombi.Api.Interfaces +{ + public interface IRadarrApi + { + RadarrAddMovie AddMovie(int tmdbId, string title, int qualityId, string rootPath, string apiKey, Uri baseUrl, bool searchNow = false); + List GetMovies(string apiKey, Uri baseUrl); + List GetProfiles(string apiKey, Uri baseUrl); + SystemStatus SystemStatus(string apiKey, Uri baseUrl); + } +} \ No newline at end of file diff --git a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj index 05c1aae09..1cc18964a 100644 --- a/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj +++ b/Ombi.Api.Interfaces/Ombi.Api.Interfaces.csproj @@ -53,6 +53,7 @@ + diff --git a/Ombi.Api.Models/Ombi.Api.Models.csproj b/Ombi.Api.Models/Ombi.Api.Models.csproj index f053da006..003b6d465 100644 --- a/Ombi.Api.Models/Ombi.Api.Models.csproj +++ b/Ombi.Api.Models/Ombi.Api.Models.csproj @@ -82,6 +82,10 @@ + + + + diff --git a/Ombi.Api.Models/Radarr/RadarrAddMovie.cs b/Ombi.Api.Models/Radarr/RadarrAddMovie.cs new file mode 100644 index 000000000..7c2000985 --- /dev/null +++ b/Ombi.Api.Models/Radarr/RadarrAddMovie.cs @@ -0,0 +1,50 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: RadarrAddMovie.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; +using Newtonsoft.Json; +using Ombi.Api.Models.Sonarr; + +namespace Ombi.Api.Models.Radarr +{ + public class RadarrAddMovie + { + + public RadarrError Error { get; set; } + public RadarrAddOptions addOptions { get; set; } + public string title { get; set; } + public string rootFolderPath { get; set; } + public int qualityProfileId { get; set; } + public bool monitored { get; set; } + public int tmdbId { get; set; } + public string cleanTitle { get; set; } + public string imdbId { get; set; } + public string titleSlug { get; set; } + public int id { get; set; } + + } +} \ No newline at end of file diff --git a/Ombi.Api.Models/Radarr/RadarrAddOptions.cs b/Ombi.Api.Models/Radarr/RadarrAddOptions.cs new file mode 100644 index 000000000..dbe7ed729 --- /dev/null +++ b/Ombi.Api.Models/Radarr/RadarrAddOptions.cs @@ -0,0 +1,35 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: RadarrAddOptions.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.Api.Models.Radarr +{ + public class RadarrAddOptions + { + public bool ignoreEpisodesWithFiles { get; set; } + public bool ignoreEpisodesWithoutFiles { get; set; } + public bool searchForMovie { get; set; } + } +} \ No newline at end of file diff --git a/Ombi.Api.Models/Radarr/RadarrError.cs b/Ombi.Api.Models/Radarr/RadarrError.cs new file mode 100644 index 000000000..73ca43f1a --- /dev/null +++ b/Ombi.Api.Models/Radarr/RadarrError.cs @@ -0,0 +1,34 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: RadarrError.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.Api.Models.Radarr +{ + public class RadarrError + { + public string message { get; set; } + public string description { get; set; } + } +} \ No newline at end of file diff --git a/Ombi.Api.Models/Radarr/RadarrMovieResponse.cs b/Ombi.Api.Models/Radarr/RadarrMovieResponse.cs new file mode 100644 index 000000000..69e48af23 --- /dev/null +++ b/Ombi.Api.Models/Radarr/RadarrMovieResponse.cs @@ -0,0 +1,80 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2017 Jamie Rees +// File: RadarrMovieResponse.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 Ombi.Api.Models.Radarr +{ + + + public class Image + { + public string coverType { get; set; } + public string url { get; set; } + } + + public class Ratings + { + public int votes { get; set; } + public double value { get; set; } + } + + public class RadarrMovieResponse + { + public string title { get; set; } + public string sortTitle { get; set; } + public int sizeOnDisk { get; set; } + public string status { get; set; } + public string overview { get; set; } + public string inCinemas { get; set; } + public string physicalRelease { get; set; } + public List images { get; set; } + public string website { get; set; } + public bool downloaded { get; set; } + public int year { get; set; } + public bool hasFile { get; set; } + public string youTubeTrailerId { get; set; } + public string studio { get; set; } + public string path { get; set; } + public int profileId { get; set; } + public bool monitored { get; set; } + public int runtime { get; set; } + public string lastInfoSync { get; set; } + public string cleanTitle { get; set; } + public string imdbId { get; set; } + public int tmdbId { get; set; } + public string titleSlug { get; set; } + public List genres { get; set; } + public List tags { get; set; } + public string added { get; set; } + public Ratings ratings { get; set; } + public List alternativeTitles { get; set; } + public int qualityProfileId { get; set; } + public int id { get; set; } + } + +} \ No newline at end of file diff --git a/Ombi.Api/Ombi.Api.csproj b/Ombi.Api/Ombi.Api.csproj index 0e60de918..27a889451 100644 --- a/Ombi.Api/Ombi.Api.csproj +++ b/Ombi.Api/Ombi.Api.csproj @@ -71,6 +71,7 @@ + diff --git a/Ombi.Api/RadarrApi.cs b/Ombi.Api/RadarrApi.cs new file mode 100644 index 000000000..92bb0435b --- /dev/null +++ b/Ombi.Api/RadarrApi.cs @@ -0,0 +1,152 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: CouchPotatoApi.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 Newtonsoft.Json; +using NLog; +using Ombi.Api.Interfaces; +using Ombi.Api.Models.Radarr; +using Ombi.Api.Models.Sonarr; +using Ombi.Helpers; +using RestSharp; + +namespace Ombi.Api +{ + public class RadarrApi : IRadarrApi + { + public RadarrApi() + { + Api = new ApiRequest(); + } + private ApiRequest Api { get; set; } + private static Logger Log = LogManager.GetCurrentClassLogger(); + + public List GetProfiles(string apiKey, Uri baseUrl) + { + var request = new RestRequest { Resource = "/api/profile", Method = Method.GET }; + + request.AddHeader("X-Api-Key", apiKey); + var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling GetProfiles for Sonarr, Retrying {0}", timespan), new TimeSpan[] { + TimeSpan.FromSeconds (2), + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(10) + }); + + var obj = policy.Execute(() => Api.ExecuteJson>(request, baseUrl)); + + return obj; + } + + public RadarrAddMovie AddMovie(int tmdbId, string title, int qualityId, string rootPath, string apiKey, Uri baseUrl, bool searchNow = false) + { + var request = new RestRequest + { + Resource = "/api/movie", + Method = Method.POST + }; + + var options = new RadarrAddMovie + { + title = title, + tmdbId = tmdbId, + qualityProfileId = qualityId, + rootFolderPath = rootPath, + titleSlug = title + + }; + + if (searchNow) + { + options.addOptions = new RadarrAddOptions + { + searchForMovie = true + }; + } + + + request.AddHeader("X-Api-Key", apiKey); + request.AddJsonBody(options); + + RadarrAddMovie result; + try + { + var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling AddSeries for Sonarr, Retrying {0}", timespan), new TimeSpan[] { + TimeSpan.FromSeconds (2) + }); + + var response = policy.Execute(() => Api.Execute(request, baseUrl)); + if (response.Content.Contains("\"message\":")) + { + var error = JsonConvert.DeserializeObject < RadarrError>(response.Content); + return new RadarrAddMovie {Error = error}; + } + return JsonConvert.DeserializeObject < RadarrAddMovie>(response.Content); + } + catch (JsonSerializationException jse) + { + Log.Error(jse); + } + return null; + } + + + public SystemStatus SystemStatus(string apiKey, Uri baseUrl) + { + var request = new RestRequest { Resource = "/api/system/status", Method = Method.GET }; + request.AddHeader("X-Api-Key", apiKey); + + var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling SystemStatus for Sonarr, Retrying {0}", timespan), new TimeSpan[] { + TimeSpan.FromSeconds (2), + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(10) + }); + + var obj = policy.Execute(() => Api.ExecuteJson(request, baseUrl)); + + return obj; + } + + + public List GetMovies(string apiKey, Uri baseUrl) + { + var request = new RestRequest { Resource = "/api/movie", Method = Method.GET }; + request.AddHeader("X-Api-Key", apiKey); + + var policy = RetryHandler.RetryAndWaitPolicy((exception, timespan) => Log.Error(exception, "Exception when calling SystemStatus for Sonarr, Retrying {0}", timespan), new TimeSpan[] { + TimeSpan.FromSeconds (2), + TimeSpan.FromSeconds(5), + TimeSpan.FromSeconds(10) + }); + + var obj = policy.Execute(() => Api.Execute(request, baseUrl)); + + return JsonConvert.DeserializeObject>(obj.Content); + } + } +} \ No newline at end of file diff --git a/Ombi.Core/Ombi.Core.csproj b/Ombi.Core/Ombi.Core.csproj index 6746f6631..f3f05b9da 100644 --- a/Ombi.Core/Ombi.Core.csproj +++ b/Ombi.Core/Ombi.Core.csproj @@ -123,6 +123,7 @@ + diff --git a/Ombi.Core/SettingModels/RadarrSettings.cs b/Ombi.Core/SettingModels/RadarrSettings.cs new file mode 100644 index 000000000..b8a6287f7 --- /dev/null +++ b/Ombi.Core/SettingModels/RadarrSettings.cs @@ -0,0 +1,37 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrSettings.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 RadarrSettings : ExternalSettings + { + public bool Enabled { get; set; } + public string ApiKey { get; set; } + public string QualityProfile { get; set; } + public string RootPath { get; set; } + + } +} \ No newline at end of file diff --git a/Ombi.UI/Ombi.UI.csproj b/Ombi.UI/Ombi.UI.csproj index 30083f4d5..524d11c81 100644 --- a/Ombi.UI/Ombi.UI.csproj +++ b/Ombi.UI/Ombi.UI.csproj @@ -792,6 +792,9 @@ Always + + Always + web.config diff --git a/Ombi.UI/Views/Admin/Radarr.cshtml b/Ombi.UI/Views/Admin/Radarr.cshtml new file mode 100644 index 000000000..bec991c71 --- /dev/null +++ b/Ombi.UI/Views/Admin/Radarr.cshtml @@ -0,0 +1,260 @@ +@using Ombi.UI.Helpers +@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase +@Html.Partial("Shared/Partial/_Sidebar") +@{ + int port; + if (Model.Port == 0) + { + port = 7878; + } + else + { + port = Model.Port; + } +} +
+
+
+ Radarr Settings + @Html.Checkbox(Model.Enabled, "Enabled", "Enabled") + + +
+ +
+ +
+
+ +
+ + +
+ +
+
+ + +
+ +
+ +
+
+ @Html.Checkbox(Model.Ssl, "Ssl", "Ssl") + + + +
+ +
+ +
+
+
+
+ +
+
+
+ +
+ +
+
+ +
+ +
+ + +
+
+ +
+
+ + @if (Model.SeasonFolders) + { + + } + else + { + + } + + +
+ +
+
+
+ +
+
+ + +
+
+ +
+
+
+
+
+ + + + \ No newline at end of file From 02a1770b3106a35358d523c5f5ee8fc2bd3df799 Mon Sep 17 00:00:00 2001 From: "Jamie.Rees" Date: Wed, 18 Jan 2017 08:39:10 +0000 Subject: [PATCH 3/4] More for #923 --- Ombi.Core/CacheKeys.cs | 1 + Ombi.UI/Modules/Admin/AdminModule.cs | 55 +++++++++++++++++++- Ombi.UI/Modules/ApplicationTesterModule.cs | 36 ++++++++++++- Ombi.UI/NinjectModules/ApiModule.cs | 1 + Ombi.UI/Startup.cs | 4 ++ Ombi.UI/Views/Admin/Radarr.cshtml | 26 ++------- Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml | 1 + 7 files changed, 99 insertions(+), 25 deletions(-) diff --git a/Ombi.Core/CacheKeys.cs b/Ombi.Core/CacheKeys.cs index 3638875eb..5e6e6c1f3 100644 --- a/Ombi.Core/CacheKeys.cs +++ b/Ombi.Core/CacheKeys.cs @@ -37,6 +37,7 @@ namespace Ombi.Core public const string PlexEpisodes = nameof(PlexEpisodes); public const string TvDbToken = nameof(TvDbToken); public const string SonarrQualityProfiles = nameof(SonarrQualityProfiles); + public const string RadarrQualityProfiles = nameof(RadarrQualityProfiles); public const string SonarrQueued = nameof(SonarrQueued); public const string SickRageQualityProfiles = nameof(SickRageQualityProfiles); public const string SickRageQueued = nameof(SickRageQueued); diff --git a/Ombi.UI/Modules/Admin/AdminModule.cs b/Ombi.UI/Modules/Admin/AdminModule.cs index c0d79d183..81b0f8422 100644 --- a/Ombi.UI/Modules/Admin/AdminModule.cs +++ b/Ombi.UI/Modules/Admin/AdminModule.cs @@ -95,6 +95,8 @@ namespace Ombi.UI.Modules.Admin private ISettingsService NotifySettings { get; } private ISettingsService DiscordSettings { get; } private IDiscordApi DiscordApi { get; } + private ISettingsService RadarrSettings { get; } + private IRadarrApi RadarrApi { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); public AdminModule(ISettingsService prService, @@ -122,7 +124,7 @@ namespace Ombi.UI.Modules.Admin ISettingsService notifyService, IRecentlyAdded recentlyAdded, ISettingsService watcherSettings , ISettingsService discord, - IDiscordApi discordapi + IDiscordApi discordapi, ISettingsService settings, IRadarrApi radarrApi , ISecurityExtensions security) : base("admin", prService, security) { PrService = prService; @@ -156,6 +158,8 @@ namespace Ombi.UI.Modules.Admin WatcherSettings = watcherSettings; DiscordSettings = discord; DiscordApi = discordapi; + RadarrSettings = settings; + RadarrApi = radarrApi; Before += (ctx) => Security.AdminLoginRedirect(Permissions.Administrator, ctx); @@ -178,11 +182,15 @@ namespace Ombi.UI.Modules.Admin Get["/sonarr"] = _ => Sonarr(); Post["/sonarr"] = _ => SaveSonarr(); + Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles(); + + Get["/radarr", true] = async (x, ct) => await Radarr(); + Post["/radarr"] = _ => SaveRadarr(); + Post["/radarrprofiles"] = _ => GetRadarrQualityProfiles(); Get["/sickrage"] = _ => Sickrage(); Post["/sickrage"] = _ => SaveSickrage(); - Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles(); Post["/cpprofiles", true] = async (x, ct) => await GetCpProfiles(); Post["/cpapikey"] = x => GetCpApiKey(); @@ -465,6 +473,49 @@ namespace Ombi.UI.Modules.Admin : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); } + private async Task Radarr() + { + var settings = await RadarrSettings.GetSettingsAsync(); + + return View["Radarr", settings]; + } + + private Response SaveRadarr() + { + var sonarrSettings = this.Bind(); + + var valid = this.Validate(sonarrSettings); + if (!valid.IsValid) + { + return Response.AsJson(valid.SendJsonError()); + } + var sickRageEnabled = SickRageService.GetSettings().Enabled; + if (sickRageEnabled) + { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "SickRage is enabled, we cannot enable Sonarr and SickRage" }); + } + sonarrSettings.ApiKey = sonarrSettings.ApiKey.Trim(); + var result = SonarrService.SaveSettings(sonarrSettings); + + return Response.AsJson(result + ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Sonarr!" } + : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); + } + + private Response GetRadarrQualityProfiles() + { + var settings = this.Bind(); + var profiles = RadarrApi.GetProfiles(settings.ApiKey, settings.FullUri); + + // set the cache + if (profiles != null) + { + Cache.Set(CacheKeys.RadarrQualityProfiles, profiles); + } + + return Response.AsJson(profiles); + } + private Negotiator Sickrage() { var settings = SickRageService.GetSettings(); diff --git a/Ombi.UI/Modules/ApplicationTesterModule.cs b/Ombi.UI/Modules/ApplicationTesterModule.cs index b0d4f2d17..a7608f547 100644 --- a/Ombi.UI/Modules/ApplicationTesterModule.cs +++ b/Ombi.UI/Modules/ApplicationTesterModule.cs @@ -46,7 +46,7 @@ namespace Ombi.UI.Modules public ApplicationTesterModule(ICouchPotatoApi cpApi, ISonarrApi sonarrApi, IPlexApi plexApi, ISickRageApi srApi, IHeadphonesApi hpApi, ISettingsService pr, ISecurityExtensions security, - IWatcherApi watcherApi) : base("test", pr, security) + IWatcherApi watcherApi, IRadarrApi radarrApi) : base("test", pr, security) { this.RequiresAuthentication(); @@ -56,9 +56,11 @@ namespace Ombi.UI.Modules SickRageApi = srApi; HeadphonesApi = hpApi; WatcherApi = watcherApi; + RadarrApi = radarrApi; Post["/cp"] = _ => CouchPotatoTest(); Post["/sonarr"] = _ => SonarrTest(); + Post["/radarr"] = _ => RadarrTest(); Post["/plex"] = _ => PlexTest(); Post["/sickrage"] = _ => SickRageTest(); Post["/headphones"] = _ => HeadphonesTest(); @@ -73,6 +75,7 @@ namespace Ombi.UI.Modules private ISickRageApi SickRageApi { get; } private IHeadphonesApi HeadphonesApi { get; } private IWatcherApi WatcherApi { get; } + private IRadarrApi RadarrApi { get; } private Response CouchPotatoTest() { @@ -148,7 +151,7 @@ namespace Ombi.UI.Modules : Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Sonarr, please check your settings." }); } - catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them. + catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them. { Log.Warn("Exception thrown when attempting to get Sonarr's status: "); Log.Warn(e); @@ -161,6 +164,35 @@ namespace Ombi.UI.Modules } } + private Response RadarrTest() + { + var radarrSettings = this.Bind(); + var valid = this.Validate(radarrSettings); + if (!valid.IsValid) + { + return Response.AsJson(valid.SendJsonError()); + } + try + { + var status = RadarrApi.SystemStatus(radarrSettings.ApiKey, radarrSettings.FullUri); + return status?.version != null + ? Response.AsJson(new JsonResponseModel { Result = true, Message = "Connected to Radarr successfully!" }) + : Response.AsJson(new JsonResponseModel { Result = false, Message = "Could not connect to Radarr, please check your settings." }); + + } + catch (Exception e) // Exceptions are expected, if we cannot connect so we will just log and swallow them. + { + Log.Warn("Exception thrown when attempting to get Radarr's status: "); + Log.Warn(e); + var message = $"Could not connect to Radarr, please check your settings. Exception Message: {e.Message}"; + if (e.InnerException != null) + { + message = $"Could not connect to Radarr, please check your settings. Exception Message: {e.InnerException.Message}"; + } + return Response.AsJson(new JsonResponseModel { Result = false, Message = message }); + } + } + private Response PlexTest() { var plexSettings = this.Bind(); diff --git a/Ombi.UI/NinjectModules/ApiModule.cs b/Ombi.UI/NinjectModules/ApiModule.cs index 9de21af99..873a3c527 100644 --- a/Ombi.UI/NinjectModules/ApiModule.cs +++ b/Ombi.UI/NinjectModules/ApiModule.cs @@ -48,6 +48,7 @@ namespace Ombi.UI.NinjectModules Bind().To(); Bind().To(); Bind().To(); + Bind().To(); } } } \ No newline at end of file diff --git a/Ombi.UI/Startup.cs b/Ombi.UI/Startup.cs index e366901c1..ff8590da4 100644 --- a/Ombi.UI/Startup.cs +++ b/Ombi.UI/Startup.cs @@ -124,6 +124,10 @@ namespace Ombi.UI var slackService = container.Get>(); var slackSettings = slackService.GetSettings(); SubScribeOvserver(slackSettings, notificationService, new SlackNotification(container.Get(), slackService)); + + var discordSettings = container.Get>(); + var discordService = discordSettings.GetSettings(); + SubScribeOvserver(discordService, notificationService, new DiscordNotification(container.Get(), discordSettings)); } private void SubScribeOvserver(T settings, INotificationService notificationService, INotification notification) diff --git a/Ombi.UI/Views/Admin/Radarr.cshtml b/Ombi.UI/Views/Admin/Radarr.cshtml index bec991c71..e0ce08d07 100644 --- a/Ombi.UI/Views/Admin/Radarr.cshtml +++ b/Ombi.UI/Views/Admin/Radarr.cshtml @@ -67,26 +67,10 @@
- +
-
-
- - @if (Model.SeasonFolders) - { - - } - else - { - - } - - -
- -
@@ -124,7 +108,7 @@ $.ajax({ type: $form.prop("method"), data: $form.serialize(), - url: "sonarrprofiles", + url: "radarrprofiles", dataType: "json", success: function(response) { response.forEach(function(result) { @@ -202,7 +186,7 @@ $.ajax({ type: $form.prop("method"), data: $form.serialize(), - url: "sonarrprofiles", + url: "radarrprofiles", dataType: "json", success: function (response) { response.forEach(function (result) { @@ -219,7 +203,7 @@ }); var base = '@Html.GetBaseUrl()'; - $('#testSonarr').click(function (e) { + $('#testRadarr').click(function (e) { $('#spinner').attr("class", "fa fa-spinner fa-spin"); e.preventDefault(); @@ -230,7 +214,7 @@ var data = $form.serialize(); data = data + "&qualityProfile=" + qualityProfile; - var url = createBaseUrl(base, '/test/sonarr'); + var url = createBaseUrl(base, '/test/radarr'); $.ajax({ type: $form.prop("method"), url: url, diff --git a/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml b/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml index d38827cf8..a2b1dc021 100644 --- a/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml +++ b/Ombi.UI/Views/Shared/Partial/_Sidebar.cshtml @@ -11,6 +11,7 @@ @Html.GetSidebarUrl(Context, "/admin/plex", "Plex") @Html.GetSidebarUrl(Context, "/admin/couchpotato", "CouchPotato") @Html.GetSidebarUrl(Context, "/admin/watcher", "Watcher (beta)") + @Html.GetSidebarUrl(Context, "/admin/radarr", "Radarr (beta)") @Html.GetSidebarUrl(Context, "/admin/sonarr", "Sonarr") @Html.GetSidebarUrl(Context, "/admin/sickrage", "SickRage") @Html.GetSidebarUrl(Context, "/admin/headphones", "Headphones (beta)") From 4926255094ae3ac26b57052e5d2f1aee60f875c1 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 18 Jan 2017 21:05:08 +0000 Subject: [PATCH 4/4] Finished #923 !!! --- Ombi.Api.Models/Radarr/RadarrAddMovie.cs | 5 + Ombi.Api/RadarrApi.cs | 4 +- Ombi.Core/CacheKeys.cs | 1 + Ombi.Core/MovieSender.cs | 30 +++++- .../SettingModels/ScheduledJobsSettings.cs | 1 + Ombi.Services/Interfaces/IRadarrCacher.cs | 11 ++ Ombi.Services/Jobs/JobNames.cs | 1 + Ombi.Services/Jobs/RadarrCacher.cs | 102 ++++++++++++++++++ Ombi.Services/Ombi.Services.csproj | 2 + Ombi.UI/Jobs/Scheduler.cs | 14 +++ Ombi.UI/Modules/Admin/AdminModule.cs | 54 +++++++--- Ombi.UI/Modules/Admin/IntegrationModule.cs | 12 +++ Ombi.UI/Modules/SearchModule.cs | 13 ++- Ombi.UI/NinjectModules/ServicesModule.cs | 1 + Ombi.UI/Ombi.UI.csproj | 1 + Ombi.UI/Validators/RadarrValidator.cs | 43 ++++++++ Ombi.UI/Views/Admin/Radarr.cshtml | 2 +- Ombi.UI/Views/Admin/SchedulerSettings.cshtml | 8 ++ 18 files changed, 283 insertions(+), 22 deletions(-) create mode 100644 Ombi.Services/Interfaces/IRadarrCacher.cs create mode 100644 Ombi.Services/Jobs/RadarrCacher.cs create mode 100644 Ombi.UI/Validators/RadarrValidator.cs diff --git a/Ombi.Api.Models/Radarr/RadarrAddMovie.cs b/Ombi.Api.Models/Radarr/RadarrAddMovie.cs index 7c2000985..5c589bd12 100644 --- a/Ombi.Api.Models/Radarr/RadarrAddMovie.cs +++ b/Ombi.Api.Models/Radarr/RadarrAddMovie.cs @@ -34,6 +34,10 @@ namespace Ombi.Api.Models.Radarr public class RadarrAddMovie { + public RadarrAddMovie() + { + images = new List(); + } public RadarrError Error { get; set; } public RadarrAddOptions addOptions { get; set; } public string title { get; set; } @@ -41,6 +45,7 @@ namespace Ombi.Api.Models.Radarr public int qualityProfileId { get; set; } public bool monitored { get; set; } public int tmdbId { get; set; } + public List images { get; set; } public string cleanTitle { get; set; } public string imdbId { get; set; } public string titleSlug { get; set; } diff --git a/Ombi.Api/RadarrApi.cs b/Ombi.Api/RadarrApi.cs index 92bb0435b..648ff87b3 100644 --- a/Ombi.Api/RadarrApi.cs +++ b/Ombi.Api/RadarrApi.cs @@ -77,8 +77,8 @@ namespace Ombi.Api tmdbId = tmdbId, qualityProfileId = qualityId, rootFolderPath = rootPath, - titleSlug = title - + titleSlug = title, + monitored = true }; if (searchNow) diff --git a/Ombi.Core/CacheKeys.cs b/Ombi.Core/CacheKeys.cs index 5e6e6c1f3..889ac6df7 100644 --- a/Ombi.Core/CacheKeys.cs +++ b/Ombi.Core/CacheKeys.cs @@ -39,6 +39,7 @@ namespace Ombi.Core public const string SonarrQualityProfiles = nameof(SonarrQualityProfiles); public const string RadarrQualityProfiles = nameof(RadarrQualityProfiles); public const string SonarrQueued = nameof(SonarrQueued); + public const string RadarrMovies = nameof(RadarrMovies); public const string SickRageQualityProfiles = nameof(SickRageQualityProfiles); public const string SickRageQueued = nameof(SickRageQueued); public const string CouchPotatoQualityProfiles = nameof(CouchPotatoQualityProfiles); diff --git a/Ombi.Core/MovieSender.cs b/Ombi.Core/MovieSender.cs index 39e2e0554..cf5b4fda3 100644 --- a/Ombi.Core/MovieSender.cs +++ b/Ombi.Core/MovieSender.cs @@ -37,16 +37,20 @@ namespace Ombi.Core public class MovieSender : IMovieSender { public MovieSender(ISettingsService cp, ISettingsService watcher, - ICouchPotatoApi cpApi, IWatcherApi watcherApi) + ICouchPotatoApi cpApi, IWatcherApi watcherApi, IRadarrApi radarrApi, ISettingsService radarrSettings) { CouchPotatoSettings = cp; WatcherSettings = watcher; CpApi = cpApi; WatcherApi = watcherApi; + RadarrSettings = radarrSettings; + RadarrApi = radarrApi; } private ISettingsService CouchPotatoSettings { get; } private ISettingsService WatcherSettings { get; } + private ISettingsService RadarrSettings { get; } + private IRadarrApi RadarrApi { get; } private ICouchPotatoApi CpApi { get; } private IWatcherApi WatcherApi { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); @@ -55,6 +59,7 @@ namespace Ombi.Core { var cpSettings = await CouchPotatoSettings.GetSettingsAsync(); var watcherSettings = await WatcherSettings.GetSettingsAsync(); + var radarrSettings = await RadarrSettings.GetSettingsAsync(); if (cpSettings.Enabled) { @@ -66,6 +71,11 @@ namespace Ombi.Core return SendToWatcher(model, watcherSettings); } + if (radarrSettings.Enabled) + { + return SendToRadarr(model, radarrSettings); + } + return new MovieSenderResult { Result = false, MovieSendingEnabled = false }; } @@ -91,5 +101,23 @@ namespace Ombi.Core var result = CpApi.AddMovie(model.ImdbId, settings.ApiKey, model.Title, settings.FullUri, qualityId); return new MovieSenderResult { Result = result, MovieSendingEnabled = true }; } + + private MovieSenderResult SendToRadarr(RequestedModel model, RadarrSettings settings) + { + var qualityProfile = 0; + int.TryParse(settings.QualityProfile, out qualityProfile); + var result = RadarrApi.AddMovie(model.ProviderId, model.Title, qualityProfile, settings.RootPath, settings.ApiKey, settings.FullUri, true); + + if (!string.IsNullOrEmpty(result.Error?.message)) + { + Log.Error(result.Error.message); + return new MovieSenderResult { Result = false }; + } + if (!string.IsNullOrEmpty(result.title)) + { + return new MovieSenderResult { Result = true, MovieSendingEnabled = true }; + } + return new MovieSenderResult { Result = false, MovieSendingEnabled = true }; + } } } \ No newline at end of file diff --git a/Ombi.Core/SettingModels/ScheduledJobsSettings.cs b/Ombi.Core/SettingModels/ScheduledJobsSettings.cs index 76921a679..a2609206b 100644 --- a/Ombi.Core/SettingModels/ScheduledJobsSettings.cs +++ b/Ombi.Core/SettingModels/ScheduledJobsSettings.cs @@ -46,5 +46,6 @@ namespace Ombi.Core.SettingModels public int FaultQueueHandler { get; set; } public int PlexContentCacher { get; set; } public int PlexUserChecker { get; set; } + public int RadarrCacher { get; set; } } } \ No newline at end of file diff --git a/Ombi.Services/Interfaces/IRadarrCacher.cs b/Ombi.Services/Interfaces/IRadarrCacher.cs new file mode 100644 index 000000000..85b2fae38 --- /dev/null +++ b/Ombi.Services/Interfaces/IRadarrCacher.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Ombi.Services.Models; + +namespace Ombi.Services.Interfaces +{ + public interface IRadarrCacher + { + void Queued(); + int[] QueuedIds(); + } +} diff --git a/Ombi.Services/Jobs/JobNames.cs b/Ombi.Services/Jobs/JobNames.cs index 06b5b32ac..8b663a8ae 100644 --- a/Ombi.Services/Jobs/JobNames.cs +++ b/Ombi.Services/Jobs/JobNames.cs @@ -32,6 +32,7 @@ namespace Ombi.Services.Jobs public const string CpCacher = "CouchPotato Cacher"; public const string WatcherCacher = "Watcher Cacher"; public const string SonarrCacher = "Sonarr Cacher"; + public const string RadarrCacher = "Radarr Cacher"; public const string SrCacher = "SickRage Cacher"; public const string PlexChecker = "Plex Availability Cacher"; public const string PlexCacher = "Plex Cacher"; diff --git a/Ombi.Services/Jobs/RadarrCacher.cs b/Ombi.Services/Jobs/RadarrCacher.cs new file mode 100644 index 000000000..7273fb626 --- /dev/null +++ b/Ombi.Services/Jobs/RadarrCacher.cs @@ -0,0 +1,102 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: PlexAvailabilityChecker.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; +using System.Linq; +using NLog; +using Ombi.Api.Interfaces; +using Ombi.Api.Models.Radarr; +using Ombi.Core; +using Ombi.Core.SettingModels; +using Ombi.Helpers; +using Ombi.Services.Interfaces; +using Quartz; + +namespace Ombi.Services.Jobs +{ + public class RadarrCacher : IJob, IRadarrCacher + { + public RadarrCacher(ISettingsService radarrService, IRadarrApi radarrApi, ICacheProvider cache, IJobRecord rec) + { + RadarrSettings = radarrService; + RadarrApi = radarrApi; + Job = rec; + Cache = cache; + } + + private ISettingsService RadarrSettings { get; } + private ICacheProvider Cache { get; } + private IRadarrApi RadarrApi { get; } + private IJobRecord Job { get; } + + private static Logger Log = LogManager.GetCurrentClassLogger(); + + public void Queued() + { + var settings = RadarrSettings.GetSettings(); + if (settings.Enabled) + { + Job.SetRunning(true, JobNames.RadarrCacher); + try + { + var movies = RadarrApi.GetMovies(settings.ApiKey, settings.FullUri); + if (movies != null) + { + var movieIds = movies.Select(x => x.tmdbId).ToList(); + Cache.Set(CacheKeys.RadarrMovies, movieIds, CacheKeys.TimeFrameMinutes.SchedulerCaching); + } + } + catch (System.Exception ex) + { + Log.Error(ex, "Failed caching queued items from Radarr"); + } + finally + { + Job.Record(JobNames.RadarrCacher); + Job.SetRunning(false, JobNames.RadarrCacher); + } + } + } + + // we do not want to set here... + public int[] QueuedIds() + { + var retVal = new List(); + var movies = Cache.Get>(CacheKeys.RadarrMovies); + if (movies != null) + { + retVal.AddRange(movies); + } + return retVal.ToArray(); + } + + public void Execute(IJobExecutionContext context) + { + Queued(); + } + } +} \ No newline at end of file diff --git a/Ombi.Services/Ombi.Services.csproj b/Ombi.Services/Ombi.Services.csproj index ec412e87f..444f86980 100644 --- a/Ombi.Services/Ombi.Services.csproj +++ b/Ombi.Services/Ombi.Services.csproj @@ -86,9 +86,11 @@ + + diff --git a/Ombi.UI/Jobs/Scheduler.cs b/Ombi.UI/Jobs/Scheduler.cs index 7450e1c86..b2c32188a 100644 --- a/Ombi.UI/Jobs/Scheduler.cs +++ b/Ombi.UI/Jobs/Scheduler.cs @@ -75,6 +75,7 @@ namespace Ombi.UI.Jobs JobBuilder.Create().WithIdentity("UserRequestLimiter", "Request").Build(), JobBuilder.Create().WithIdentity("RecentlyAddedModel", "Email").Build(), JobBuilder.Create().WithIdentity("FaultQueueHandler", "Fault").Build(), + JobBuilder.Create().WithIdentity("RadarrCacher", "Cache").Build(), }; jobs.AddRange(jobList); @@ -170,6 +171,10 @@ namespace Ombi.UI.Jobs { s.PlexUserChecker = 24; } + if (s.RadarrCacher == 0) + { + s.RadarrCacher = 60; + } var triggers = new List(); @@ -222,6 +227,14 @@ namespace Ombi.UI.Jobs .WithSimpleSchedule(x => x.WithIntervalInMinutes(s.WatcherCacher).RepeatForever()) .Build(); + var radarrCacher = + TriggerBuilder.Create() + .WithIdentity("RadarrCacher", "Cache") + .StartNow() + //.StartAt(DateBuilder.FutureDate(2, IntervalUnit.Minute)) + .WithSimpleSchedule(x => x.WithIntervalInMinutes(s.RadarrCacher).RepeatForever()) + .Build(); + var storeBackup = TriggerBuilder.Create() .WithIdentity("StoreBackup", "Database") @@ -280,6 +293,7 @@ namespace Ombi.UI.Jobs triggers.Add(fault); triggers.Add(plexCacher); triggers.Add(plexUserChecker); + triggers.Add(radarrCacher); return triggers; } diff --git a/Ombi.UI/Modules/Admin/AdminModule.cs b/Ombi.UI/Modules/Admin/AdminModule.cs index 81b0f8422..06533b7d3 100644 --- a/Ombi.UI/Modules/Admin/AdminModule.cs +++ b/Ombi.UI/Modules/Admin/AdminModule.cs @@ -175,7 +175,7 @@ namespace Ombi.UI.Modules.Admin Get["/getusers"] = _ => GetUsers(); Get["/couchpotato"] = _ => CouchPotato(); - Post["/couchpotato"] = _ => SaveCouchPotato(); + Post["/couchpotato", true] = async (x, ct) => await SaveCouchPotato(); Get["/plex"] = _ => Plex(); Post["/plex", true] = async (x, ct) => await SavePlex(); @@ -185,7 +185,7 @@ namespace Ombi.UI.Modules.Admin Post["/sonarrprofiles"] = _ => GetSonarrQualityProfiles(); Get["/radarr", true] = async (x, ct) => await Radarr(); - Post["/radarr"] = _ => SaveRadarr(); + Post["/radarr", true] = async (x, ct) => await SaveRadarr(); Post["/radarrprofiles"] = _ => GetRadarrQualityProfiles(); Get["/sickrage"] = _ => Sickrage(); @@ -385,7 +385,7 @@ namespace Ombi.UI.Modules.Admin return View["CouchPotato", settings]; } - private Response SaveCouchPotato() + private async Task SaveCouchPotato() { var couchPotatoSettings = this.Bind(); var valid = this.Validate(couchPotatoSettings); @@ -394,7 +394,7 @@ namespace Ombi.UI.Modules.Admin return Response.AsJson(valid.SendJsonError()); } - var watcherSettings = WatcherSettings.GetSettings(); + var watcherSettings = await WatcherSettings.GetSettingsAsync(); if (watcherSettings.Enabled) { @@ -406,8 +406,20 @@ namespace Ombi.UI.Modules.Admin }); } + var radarrSettings = await RadarrSettings.GetSettingsAsync(); + + if (radarrSettings.Enabled) + { + return + Response.AsJson(new JsonResponseModel + { + Result = false, + Message = "Cannot have Radarr and CouchPotato both enabled." + }); + } + couchPotatoSettings.ApiKey = couchPotatoSettings.ApiKey.Trim(); - var result = CpService.SaveSettings(couchPotatoSettings); + var result = await CpService.SaveSettingsAsync(couchPotatoSettings); return Response.AsJson(result ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for CouchPotato!" } : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); @@ -465,6 +477,7 @@ namespace Ombi.UI.Modules.Admin { return Response.AsJson(new JsonResponseModel { Result = false, Message = "SickRage is enabled, we cannot enable Sonarr and SickRage" }); } + sonarrSettings.ApiKey = sonarrSettings.ApiKey.Trim(); var result = SonarrService.SaveSettings(sonarrSettings); @@ -480,25 +493,34 @@ namespace Ombi.UI.Modules.Admin return View["Radarr", settings]; } - private Response SaveRadarr() + private async Task SaveRadarr() { - var sonarrSettings = this.Bind(); + var radarrSettings = this.Bind(); - var valid = this.Validate(sonarrSettings); - if (!valid.IsValid) + //Check Watcher and CP make sure they are not enabled + var watcher = await WatcherSettings.GetSettingsAsync(); + if (watcher.Enabled) { - return Response.AsJson(valid.SendJsonError()); + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Watcher is enabled, we cannot enable Watcher and Radarr" }); } - var sickRageEnabled = SickRageService.GetSettings().Enabled; - if (sickRageEnabled) + + var cp = await CpService.GetSettingsAsync(); + if (cp.Enabled) { - return Response.AsJson(new JsonResponseModel { Result = false, Message = "SickRage is enabled, we cannot enable Sonarr and SickRage" }); + return Response.AsJson(new JsonResponseModel { Result = false, Message = "CouchPotato is enabled, we cannot enable Watcher and CouchPotato" }); } - sonarrSettings.ApiKey = sonarrSettings.ApiKey.Trim(); - var result = SonarrService.SaveSettings(sonarrSettings); + + var valid = this.Validate(radarrSettings); + if (!valid.IsValid) + { + return Response.AsJson(valid.SendJsonError()); + } + + radarrSettings.ApiKey = radarrSettings.ApiKey.Trim(); + var result = await RadarrSettings.SaveSettingsAsync(radarrSettings); return Response.AsJson(result - ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Sonarr!" } + ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Radarr!" } : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); } diff --git a/Ombi.UI/Modules/Admin/IntegrationModule.cs b/Ombi.UI/Modules/Admin/IntegrationModule.cs index 9cc718e40..b8a91e520 100644 --- a/Ombi.UI/Modules/Admin/IntegrationModule.cs +++ b/Ombi.UI/Modules/Admin/IntegrationModule.cs @@ -97,6 +97,18 @@ namespace Ombi.UI.Modules.Admin }); } + var watcherSettings = await WatcherSettings.GetSettingsAsync(); + + if (watcherSettings.Enabled) + { + return + Response.AsJson(new JsonResponseModel + { + Result = false, + Message = "Cannot have Watcher and CouchPotato both enabled." + }); + } + settings.ApiKey = settings.ApiKey.Trim(); var result = await WatcherSettings.SaveSettingsAsync(settings); return Response.AsJson(result diff --git a/Ombi.UI/Modules/SearchModule.cs b/Ombi.UI/Modules/SearchModule.cs index 30acdf68a..b64b586f8 100644 --- a/Ombi.UI/Modules/SearchModule.cs +++ b/Ombi.UI/Modules/SearchModule.cs @@ -76,7 +76,7 @@ namespace Ombi.UI.Modules ISettingsService plexService, ISettingsService auth, IRepository u, ISettingsService email, IIssueService issue, IAnalytics a, IRepository rl, ITransientFaultQueue tfQueue, IRepository content, - ISecurityExtensions security, IMovieSender movieSender) + ISecurityExtensions security, IMovieSender movieSender, IRadarrCacher radarrCacher) : base("search", prSettings, security) { Auth = auth; @@ -108,6 +108,7 @@ namespace Ombi.UI.Modules PlexContentRepository = content; MovieSender = movieSender; WatcherCacher = watcherCacher; + RadarrCacher = radarrCacher; Get["SearchIndex", "/", true] = async (x, ct) => await RequestLoad(); @@ -157,6 +158,7 @@ namespace Ombi.UI.Modules private IAnalytics Analytics { get; } private ITransientFaultQueue FaultQueue { get; } private IRepository RequestLimitRepo { get; } + private IRadarrCacher RadarrCacher { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); private async Task RequestLoad() @@ -236,6 +238,7 @@ namespace Ombi.UI.Modules var cpCached = CpCacher.QueuedIds(); var watcherCached = WatcherCacher.QueuedIds(); + var radarrCached = RadarrCacher.QueuedIds(); var content = PlexContentRepository.GetAll(); var plexMovies = Checker.GetPlexMovies(content); var viewMovies = new List(); @@ -288,13 +291,19 @@ namespace Ombi.UI.Modules } else if (cpCached.Contains(movie.Id) && canSee) // compare to the couchpotato db { + viewMovie.Approved = true; viewMovie.Requested = true; } else if(watcherCached.Contains(imdbId) && canSee) // compare to the watcher db { + viewMovie.Approved = true; + viewMovie.Requested = true; + } + else if (radarrCached.Contains(movie.Id) && canSee) + { + viewMovie.Approved = true; viewMovie.Requested = true; } - viewMovies.Add(viewMovie); } diff --git a/Ombi.UI/NinjectModules/ServicesModule.cs b/Ombi.UI/NinjectModules/ServicesModule.cs index 7c5f9095a..3b02a0213 100644 --- a/Ombi.UI/NinjectModules/ServicesModule.cs +++ b/Ombi.UI/NinjectModules/ServicesModule.cs @@ -48,6 +48,7 @@ namespace Ombi.UI.NinjectModules Bind().To(); Bind().To(); Bind().To(); + Bind().To(); Bind().To(); Bind().To(); Bind().To(); diff --git a/Ombi.UI/Ombi.UI.csproj b/Ombi.UI/Ombi.UI.csproj index 524d11c81..ce3f1453b 100644 --- a/Ombi.UI/Ombi.UI.csproj +++ b/Ombi.UI/Ombi.UI.csproj @@ -288,6 +288,7 @@ + diff --git a/Ombi.UI/Validators/RadarrValidator.cs b/Ombi.UI/Validators/RadarrValidator.cs new file mode 100644 index 000000000..75550c787 --- /dev/null +++ b/Ombi.UI/Validators/RadarrValidator.cs @@ -0,0 +1,43 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrValidator.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 FluentValidation; +using Ombi.Core.SettingModels; + +namespace Ombi.UI.Validators +{ + public class RadarrValidator : AbstractValidator + { + public RadarrValidator() + { + RuleFor(request => request.ApiKey).NotEmpty().WithMessage("You must specify a Api Key."); + RuleFor(request => request.Ip).NotEmpty().WithMessage("You must specify a IP/Host name."); + RuleFor(request => request.Port).NotEmpty().WithMessage("You must specify a Port."); + RuleFor(request => request.QualityProfile).NotEmpty().WithMessage("You must specify a Quality Profile."); + } + } +} \ No newline at end of file diff --git a/Ombi.UI/Views/Admin/Radarr.cshtml b/Ombi.UI/Views/Admin/Radarr.cshtml index e0ce08d07..3d4520e68 100644 --- a/Ombi.UI/Views/Admin/Radarr.cshtml +++ b/Ombi.UI/Views/Admin/Radarr.cshtml @@ -73,7 +73,7 @@
- +
diff --git a/Ombi.UI/Views/Admin/SchedulerSettings.cshtml b/Ombi.UI/Views/Admin/SchedulerSettings.cshtml index 0c0b0200a..9ba6ed904 100644 --- a/Ombi.UI/Views/Admin/SchedulerSettings.cshtml +++ b/Ombi.UI/Views/Admin/SchedulerSettings.cshtml @@ -45,6 +45,14 @@
+
+ + +
+
+ + +
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.