diff --git a/PlexRequests.Api.Interfaces/ISonarrApi.cs b/PlexRequests.Api.Interfaces/ISonarrApi.cs index d9d49d10e..74ec72d1c 100644 --- a/PlexRequests.Api.Interfaces/ISonarrApi.cs +++ b/PlexRequests.Api.Interfaces/ISonarrApi.cs @@ -34,5 +34,8 @@ namespace PlexRequests.Api.Interfaces public interface ISonarrApi { List GetProfiles(string apiKey, Uri baseUrl); + + SonarrAddSeries AddSeries(int tvdbId, string title, int qualityId, bool seasonFolders, string rootPath, + bool episodes, string apiKey, Uri baseUrl); } } \ 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 c12da3add..79683c5fe 100644 --- a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj +++ b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj @@ -48,6 +48,7 @@ + diff --git a/PlexRequests.Api.Models/Sonarr/SonarrAddSeries.cs b/PlexRequests.Api.Models/Sonarr/SonarrAddSeries.cs new file mode 100644 index 000000000..534f3068f --- /dev/null +++ b/PlexRequests.Api.Models/Sonarr/SonarrAddSeries.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +namespace PlexRequests.Api.Models.Sonarr +{ + public class Season + { + public int seasonNumber { get; set; } + public bool monitored { get; set; } + } + + public class SonarrAddSeries + { + public AddOptions addOptions { get; set; } + public string title { get; set; } + public List seasons { get; set; } + public string rootFolderPath { get; set; } + public int qualityProfileId { get; set; } + public bool seasonFolder { get; set; } + public bool monitored { get; set; } + public int tvdbId { get; set; } + public int tvRageId { get; set; } + public string cleanTitle { get; set; } + public string imdbId { get; set; } + public string titleSlug { get; set; } + public int id { get; set; } + } + + public class AddOptions + { + public bool ignoreEpisodesWithFiles { get; set; } + public bool ignoreEpisodesWithoutFiles { get; set; } + public bool searchForMissingEpisodes { get; set; } + } + + + +} diff --git a/PlexRequests.Api/MockApiData.Designer.cs b/PlexRequests.Api/MockApiData.Designer.cs index 590b1af35..0b729f577 100644 --- a/PlexRequests.Api/MockApiData.Designer.cs +++ b/PlexRequests.Api/MockApiData.Designer.cs @@ -60,6 +60,43 @@ namespace PlexRequests.Api { } } + /// + /// Looks up a localized string similar to { + /// "title": "Archer (2009)", + /// "seasons": [ + /// { + /// "seasonNumber": 5, + /// "monitored": true + /// }, + /// { + /// "seasonNumber": 4, + /// "monitored": true + /// }, + /// { + /// "seasonNumber": 3, + /// "monitored": true + /// }, + /// { + /// "seasonNumber": 2, + /// "monitored": true + /// }, + /// { + /// "seasonNumber": 1, + /// "monitored": true + /// }, + /// { + /// "seasonNumber": 0, + /// "monitored": false + /// } + /// ], + /// "pat [rest of string was truncated]";. + /// + internal static string Sonarr_AddSeriesResult { + get { + return ResourceManager.GetString("Sonarr_AddSeriesResult", resourceCulture); + } + } + /// /// Looks up a localized string similar to [ /// { diff --git a/PlexRequests.Api/MockApiData.resx b/PlexRequests.Api/MockApiData.resx index 2380d9a92..ead341dac 100644 --- a/PlexRequests.Api/MockApiData.resx +++ b/PlexRequests.Api/MockApiData.resx @@ -117,6 +117,47 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + { + "title": "Archer (2009)", + "seasons": [ + { + "seasonNumber": 5, + "monitored": true + }, + { + "seasonNumber": 4, + "monitored": true + }, + { + "seasonNumber": 3, + "monitored": true + }, + { + "seasonNumber": 2, + "monitored": true + }, + { + "seasonNumber": 1, + "monitored": true + }, + { + "seasonNumber": 0, + "monitored": false + } + ], + "path": "T:\\Archer (2009)", + "qualityProfileId": 1, + "seasonFolder": true, + "monitored": true, + "tvdbId": 110381, + "tvRageId": 23354, + "cleanTitle": "archer2009", + "imdbId": "tt1486217", + "titleSlug": "archer-2009", + "id": 1 + } + [ { diff --git a/PlexRequests.Api/Mocks/MockSonarrApi.cs b/PlexRequests.Api/Mocks/MockSonarrApi.cs index 9d565080c..1d9622467 100644 --- a/PlexRequests.Api/Mocks/MockSonarrApi.cs +++ b/PlexRequests.Api/Mocks/MockSonarrApi.cs @@ -42,5 +42,13 @@ namespace PlexRequests.Api.Mocks var obj = JsonConvert.DeserializeObject>(json); return obj; } + + public SonarrAddSeries AddSeries(int tvdbId, string title, int qualityId, bool seasonFolders, string rootPath, bool episodes, + string apiKey, Uri baseUrl) + { + var json = MockApiData.Sonarr_AddSeriesResult; + var obj = JsonConvert.DeserializeObject(json); + return obj; + } } } \ No newline at end of file diff --git a/PlexRequests.Api/SonarrApi.cs b/PlexRequests.Api/SonarrApi.cs index f6934e247..81a0fb5d8 100644 --- a/PlexRequests.Api/SonarrApi.cs +++ b/PlexRequests.Api/SonarrApi.cs @@ -45,7 +45,7 @@ namespace PlexRequests.Api public List GetProfiles(string apiKey, Uri baseUrl) { - var request = new RestRequest { Resource = "/api/profile", Method = Method.GET}; + var request = new RestRequest { Resource = "/api/profile", Method = Method.GET }; request.AddHeader("X-Api-Key", apiKey); @@ -53,5 +53,50 @@ namespace PlexRequests.Api return obj; } + + public SonarrAddSeries AddSeries(int tvdbId, string title, int qualityId, bool seasonFolders, string rootPath, bool episodes, string apiKey, Uri baseUrl) + { + + var request = new RestRequest + { + Resource = "/api/Series?", + Method = Method.POST + }; + + var options = new SonarrAddSeries(); + if (episodes == true) + { + options.addOptions = new AddOptions + { + ignoreEpisodesWithFiles = true, + ignoreEpisodesWithoutFiles = true, + searchForMissingEpisodes = false + }; + } + else + { + options.addOptions = new AddOptions + { + ignoreEpisodesWithFiles = false, + searchForMissingEpisodes = true, + ignoreEpisodesWithoutFiles = false + }; + } + options.seasonFolder = seasonFolders; + options.title = title; + options.qualityProfileId = qualityId; + options.tvdbId = tvdbId; + options.titleSlug = title; + options.seasons = new List(); + options.rootFolderPath = rootPath; + + + request.AddHeader("X-Api-Key", apiKey); + request.AddJsonBody(options); + + var obj = Api.ExecuteJson(request, baseUrl); + + return obj; + } } } \ No newline at end of file diff --git a/PlexRequests.Core/SettingModels/SonarrSettings.cs b/PlexRequests.Core/SettingModels/SonarrSettings.cs index cc5ca120d..4441d48d2 100644 --- a/PlexRequests.Core/SettingModels/SonarrSettings.cs +++ b/PlexRequests.Core/SettingModels/SonarrSettings.cs @@ -37,6 +37,8 @@ namespace PlexRequests.Core.SettingModels public int Port { get; set; } public string ApiKey { get; set; } public string QualityProfile { get; set; } + public bool SeasonFolders { get; set; } + public string RootPath { get; set; } [JsonIgnore] public Uri FullUri diff --git a/PlexRequests.Store/DbConfiguration.cs b/PlexRequests.Store/DbConfiguration.cs index d0d5cd16e..7b6c6c244 100644 --- a/PlexRequests.Store/DbConfiguration.cs +++ b/PlexRequests.Store/DbConfiguration.cs @@ -58,7 +58,7 @@ namespace PlexRequests.Store return false; } - public string DbFile = "RequestPlex.sqlite"; + public string DbFile = "PlexRequests.sqlite"; /// /// Gets the database connection. diff --git a/PlexRequests.Store/RequestedModel.cs b/PlexRequests.Store/RequestedModel.cs index e32f75766..acc76320d 100644 --- a/PlexRequests.Store/RequestedModel.cs +++ b/PlexRequests.Store/RequestedModel.cs @@ -23,6 +23,7 @@ namespace PlexRequests.Store public bool Available { get; set; } public IssueState Issues { get; set; } public string OtherMessage { get; set; } + public bool LatestTv { get; set; } } public enum RequestType diff --git a/PlexRequests.Store/SqlTables.sql b/PlexRequests.Store/SqlTables.sql index 1695445d3..1ea81ddce 100644 --- a/PlexRequests.Store/SqlTables.sql +++ b/PlexRequests.Store/SqlTables.sql @@ -28,6 +28,7 @@ CREATE TABLE IF NOT EXISTS Requested ReleaseDate varchar(50) NOT NULL, Status varchar(50) NOT NULL, Approved INTEGER NOT NULL, + LatestTv INTEGER NOT NULL, RequestedBy varchar(50), RequestedDate varchar(50) NOT NULL, Available INTEGER(50), diff --git a/PlexRequests.UI/Modules/ApprovalModule.cs b/PlexRequests.UI/Modules/ApprovalModule.cs index 2c11b46b5..57bddf2cd 100644 --- a/PlexRequests.UI/Modules/ApprovalModule.cs +++ b/PlexRequests.UI/Modules/ApprovalModule.cs @@ -44,13 +44,16 @@ namespace PlexRequests.UI.Modules public class ApprovalModule : BaseModule { - public ApprovalModule(IRepository service, ISettingsService cpService, ICouchPotatoApi cpApi) : base("approval") + public ApprovalModule(IRepository service, ISettingsService cpService, ICouchPotatoApi cpApi, ISonarrApi sonarrApi, + ISettingsService sonarrSettings) : base("approval") { this.RequiresAuthentication(); Service = service; CpService = cpService; CpApi = cpApi; + SonarrApi = sonarrApi; + SonarrSettings = sonarrSettings; Post["/approve"] = parameters => Approve((int)Request.Form.requestid); Post["/approveall"] = x => ApproveAll(); @@ -59,7 +62,9 @@ namespace PlexRequests.UI.Modules private IRepository Service { get; set; } private static Logger Log = LogManager.GetCurrentClassLogger(); + private ISettingsService SonarrSettings { get; set; } private ISettingsService CpService { get; } + private ISonarrApi SonarrApi { get; set; } private ICouchPotatoApi CpApi { get; } /// @@ -95,8 +100,21 @@ namespace PlexRequests.UI.Modules private Response RequestTvAndUpdateStatus(RequestedModel request) { - // TODO - return Response.AsJson(new JsonResponseModel()); + var sonarrSettings = SonarrSettings.GetSettings(); + int qualityProfile; + int.TryParse(sonarrSettings.QualityProfile, out qualityProfile); + var result = SonarrApi.AddSeries(request.ProviderId, request.Title, qualityProfile, + sonarrSettings.SeasonFolders, sonarrSettings.RootPath, request.LatestTv, sonarrSettings.ApiKey, + sonarrSettings.FullUri); + + if (!string.IsNullOrEmpty(result.title)) + { + return Response.AsJson(new JsonResponseModel { Result = true }); + } + return Response.AsJson(new JsonResponseModel + { + Result = false, Message = "Could not add the series to Sonarr" + }); } private Response RequestMovieAndUpdateStatus(RequestedModel request) diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index ecf68e21f..c3c6e9fbd 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -32,6 +32,7 @@ using Nancy.Responses.Negotiation; using NLog; using PlexRequests.Api; +using PlexRequests.Api.Interfaces; using PlexRequests.Core; using PlexRequests.Core.SettingModels; using PlexRequests.Helpers; @@ -46,7 +47,7 @@ namespace PlexRequests.UI.Modules { public SearchModule(ICacheProvider cache, ISettingsService cpSettings, ISettingsService prSettings, IAvailabilityChecker checker, - IRequestService request) : base("search") + IRequestService request, ISonarrApi sonarrApi, ISettingsService sonarrSettings) : base("search") { CpService = cpSettings; PrService = prSettings; @@ -55,6 +56,8 @@ namespace PlexRequests.UI.Modules Cache = cache; Checker = checker; RequestService = request; + SonarrApi = sonarrApi; + SonarrService = sonarrSettings; Get["/"] = parameters => RequestLoad(); @@ -68,11 +71,13 @@ namespace PlexRequests.UI.Modules Post["request/tv"] = parameters => RequestTvShow((int)Request.Form.tvId, (bool)Request.Form.latest); } private TheMovieDbApi MovieApi { get; } + private ISonarrApi SonarrApi { get; } private TheTvDbApi TvApi { get; } private IRequestService RequestService { get; } private ICacheProvider Cache { get; } private ISettingsService CpService { get; } private ISettingsService PrService { get; } + private ISettingsService SonarrService { get; } private IAvailabilityChecker Checker { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); private string AuthToken => Cache.GetOrSet(CacheKeys.TvDbToken, TvApi.Authenticate, 50); @@ -257,10 +262,26 @@ namespace PlexRequests.UI.Modules RequestedDate = DateTime.Now, Approved = false, RequestedBy = Session[SessionKeys.UsernameKey].ToString(), - Issues = IssueState.None + Issues = IssueState.None, + LatestTv = latest }; RequestService.AddRequest(showId, model); + + var settings = PrService.GetSettings(); + if (!settings.RequireApproval) + { + var sonarrSettings = SonarrService.GetSettings(); + int qualityProfile; + int.TryParse(sonarrSettings.QualityProfile, out qualityProfile); + var result = SonarrApi.AddSeries(model.ProviderId, model.Title, qualityProfile, + sonarrSettings.SeasonFolders, sonarrSettings.RootPath, model.LatestTv, sonarrSettings.ApiKey, + sonarrSettings.FullUri); + Log.Info("Added series {0} to Sonarr, Result: {1}", model.Title, result); + Log.Trace("Model sent to Sonarr: "); + Log.Trace(model.DumpJson()); + } + return Response.AsJson(new { Result = true }); } private string GetAuthToken(TheTvDbApi api) diff --git a/PlexRequests.UI/Views/Admin/Authentication.cshtml b/PlexRequests.UI/Views/Admin/Authentication.cshtml index bcb1388dc..a703431b8 100644 --- a/PlexRequests.UI/Views/Admin/Authentication.cshtml +++ b/PlexRequests.UI/Views/Admin/Authentication.cshtml @@ -42,7 +42,7 @@
- +
@@ -58,7 +58,7 @@
- +
diff --git a/PlexRequests.UI/Views/Admin/Sonarr.cshtml b/PlexRequests.UI/Views/Admin/Sonarr.cshtml index 22380db7e..60c490a91 100644 --- a/PlexRequests.UI/Views/Admin/Sonarr.cshtml +++ b/PlexRequests.UI/Views/Admin/Sonarr.cshtml @@ -3,7 +3,7 @@ int port; if (Model.Port == 0) { - port = 80; + port = 8989; } else { @@ -50,6 +50,31 @@ +
+ +
+ + +
+
+ +
+
+ +
+
+