From 5f67302b32411a8eb64b8f4534c9c24cc26e101b Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Fri, 8 Apr 2016 10:05:09 -0500 Subject: [PATCH] #150 sonarr/sickrage cache checking. sickrage has a couple small items left --- PlexRequests.Api.Interfaces/ISickRageApi.cs | 2 + PlexRequests.Api.Interfaces/ISonarrApi.cs | 2 + .../PlexRequests.Api.Models.csproj | 1 + .../Sonarr/SonarrAddSeries.cs | 15 +++- .../Sonarr/SonarrAllSeries.cs | 69 ++++++++++++++++ PlexRequests.Api/Mocks/MockSonarrApi.cs | 5 ++ PlexRequests.Api/SickrageApi.cs | 21 +++++ PlexRequests.Api/SonarrApi.cs | 9 +++ PlexRequests.Core/CacheKeys.cs | 4 + .../Interfaces/ISickRageCacher.cs | 8 ++ .../Interfaces/ISonarrCacher.cs | 8 ++ PlexRequests.Services/MediaCacheService.cs | 8 ++ .../PlexRequests.Services.csproj | 4 + PlexRequests.Services/SickRageCacher.cs | 78 +++++++++++++++++++ PlexRequests.Services/SonarrCacher.cs | 77 ++++++++++++++++++ PlexRequests.UI/Bootstrapper.cs | 2 + PlexRequests.UI/Modules/SearchModule.cs | 28 +++++-- 17 files changed, 332 insertions(+), 9 deletions(-) create mode 100644 PlexRequests.Api.Models/Sonarr/SonarrAllSeries.cs create mode 100644 PlexRequests.Services/Interfaces/ISickRageCacher.cs create mode 100644 PlexRequests.Services/Interfaces/ISonarrCacher.cs create mode 100644 PlexRequests.Services/SickRageCacher.cs create mode 100644 PlexRequests.Services/SonarrCacher.cs diff --git a/PlexRequests.Api.Interfaces/ISickRageApi.cs b/PlexRequests.Api.Interfaces/ISickRageApi.cs index 4953b16f6..5d10d7557 100644 --- a/PlexRequests.Api.Interfaces/ISickRageApi.cs +++ b/PlexRequests.Api.Interfaces/ISickRageApi.cs @@ -39,5 +39,7 @@ namespace PlexRequests.Api.Interfaces SickRagePing Ping(string apiKey, Uri baseUrl); Task AddSeason(int tvdbId, int season, string apiKey, Uri baseUrl); + + Task GetShows(string apiKey, Uri baseUrl); } } \ No newline at end of file diff --git a/PlexRequests.Api.Interfaces/ISonarrApi.cs b/PlexRequests.Api.Interfaces/ISonarrApi.cs index e4dce0c3a..7e888f91a 100644 --- a/PlexRequests.Api.Interfaces/ISonarrApi.cs +++ b/PlexRequests.Api.Interfaces/ISonarrApi.cs @@ -39,5 +39,7 @@ namespace PlexRequests.Api.Interfaces int seasonCount, int[] seasons, string apiKey, Uri baseUrl); SystemStatus SystemStatus(string apiKey, Uri baseUrl); + + List GetSeries(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 ec15e83d1..e109a6d3d 100644 --- a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj +++ b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj @@ -74,6 +74,7 @@ + diff --git a/PlexRequests.Api.Models/Sonarr/SonarrAddSeries.cs b/PlexRequests.Api.Models/Sonarr/SonarrAddSeries.cs index 6d143fc55..d489fca2b 100644 --- a/PlexRequests.Api.Models/Sonarr/SonarrAddSeries.cs +++ b/PlexRequests.Api.Models/Sonarr/SonarrAddSeries.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; +using System; namespace PlexRequests.Api.Models.Sonarr { @@ -8,6 +9,17 @@ namespace PlexRequests.Api.Models.Sonarr { public int seasonNumber { get; set; } public bool monitored { get; set; } + public Statistics statistics { get; set; } + } + + public class Statistics + { + public int episodeFileCount { get; set; } + public int episodeCount { get; set; } + public int totalEpisodeCount { get; set; } + public long sizeOnDisk { get; set; } + public float percentOfEpisodes { get; set; } + public DateTime previousAiring { get; set; } } public class SonarrAddSeries @@ -35,7 +47,4 @@ namespace PlexRequests.Api.Models.Sonarr public bool ignoreEpisodesWithoutFiles { get; set; } public bool searchForMissingEpisodes { get; set; } } - - - } diff --git a/PlexRequests.Api.Models/Sonarr/SonarrAllSeries.cs b/PlexRequests.Api.Models/Sonarr/SonarrAllSeries.cs new file mode 100644 index 000000000..f788d18b7 --- /dev/null +++ b/PlexRequests.Api.Models/Sonarr/SonarrAllSeries.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; + +namespace PlexRequests.Api.Models.Sonarr +{ + public class SonarrAllSeries + { + public List list { get; set; } + } + + public class Series + { + public string title { get; set; } + public List alternateTitles { get; set; } + public string sortTitle { get; set; } + public int seasonCount { get; set; } + public int totalEpisodeCount { get; set; } + public int episodeCount { get; set; } + public int episodeFileCount { get; set; } + public long sizeOnDisk { get; set; } + public string status { get; set; } + public string overview { get; set; } + public DateTime previousAiring { get; set; } + public string network { get; set; } + public List images { get; set; } + public List seasons { get; set; } + public int year { get; set; } + public string path { get; set; } + public int profileId { get; set; } + public bool seasonFolder { get; set; } + public bool monitored { get; set; } + public bool useSceneNumbering { get; set; } + public int runtime { get; set; } + public int tvdbId { get; set; } + public int tvRageId { get; set; } + public int tvMazeId { get; set; } + public DateTime firstAired { get; set; } + public DateTime lastInfoSync { get; set; } + public string seriesType { get; set; } + public string cleanTitle { get; set; } + public string imdbId { get; set; } + public string titleSlug { get; set; } + public string certification { get; set; } + public List genres { get; set; } + public List tags { get; set; } + public DateTime added { get; set; } + public Ratings ratings { get; set; } + public int qualityProfileId { get; set; } + public int id { get; set; } + } + + public class Ratings + { + public int votes { get; set; } + public float value { get; set; } + } + + public class Alternatetitle + { + public string title { get; set; } + public int seasonNumber { get; set; } + } + + public class Image + { + public string coverType { get; set; } + public string url { get; set; } + } +} diff --git a/PlexRequests.Api/Mocks/MockSonarrApi.cs b/PlexRequests.Api/Mocks/MockSonarrApi.cs index dfb816f8a..abe8e793b 100644 --- a/PlexRequests.Api/Mocks/MockSonarrApi.cs +++ b/PlexRequests.Api/Mocks/MockSonarrApi.cs @@ -55,5 +55,10 @@ namespace PlexRequests.Api.Mocks { throw new NotImplementedException(); } + + public List GetSeries(string apiKey, Uri baseUrl) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/PlexRequests.Api/SickrageApi.cs b/PlexRequests.Api/SickrageApi.cs index 223d3115d..68a501a04 100644 --- a/PlexRequests.Api/SickrageApi.cs +++ b/PlexRequests.Api/SickrageApi.cs @@ -38,6 +38,7 @@ using PlexRequests.Api.Interfaces; using PlexRequests.Api.Models.SickRage; using PlexRequests.Helpers; using RestSharp; +using Newtonsoft.Json.Linq; namespace PlexRequests.Api { @@ -206,5 +207,25 @@ namespace PlexRequests.Api return result; }).ConfigureAwait(false); } + + public async Task GetShows(string apiKey, Uri baseUrl) // TODO: get the correct response/models from SR + { + var request = new RestRequest + { + Resource = "/api/{apiKey}/?cmd=shows", + Method = Method.GET + }; + request.AddUrlSegment("apiKey", apiKey); + + //await Task.Run(() => Thread.Sleep(2000)); + //return await Task.Run(() => + //{ + //Log.Trace("Entering `Execute` in a new `Task`"); + var result = Api.ExecuteJson(request, baseUrl); + + //Log.Trace("Exiting `Execute` and yeilding `Task` result"); + return null; + //}).ConfigureAwait(false); + } } } \ No newline at end of file diff --git a/PlexRequests.Api/SonarrApi.cs b/PlexRequests.Api/SonarrApi.cs index 91b9be55e..e9e1e96ad 100644 --- a/PlexRequests.Api/SonarrApi.cs +++ b/PlexRequests.Api/SonarrApi.cs @@ -36,6 +36,7 @@ using PlexRequests.Api.Models.Sonarr; using PlexRequests.Helpers; using RestSharp; +using Newtonsoft.Json.Linq; namespace PlexRequests.Api { @@ -122,5 +123,13 @@ namespace PlexRequests.Api return obj; } + + public List GetSeries(string apiKey, Uri baseUrl) + { + var request = new RestRequest { Resource = "/api/series", Method = Method.GET }; + request.AddHeader("X-Api-Key", apiKey); + + return Api.Execute>(request, baseUrl); + } } } \ No newline at end of file diff --git a/PlexRequests.Core/CacheKeys.cs b/PlexRequests.Core/CacheKeys.cs index dfa07891c..3da5be381 100644 --- a/PlexRequests.Core/CacheKeys.cs +++ b/PlexRequests.Core/CacheKeys.cs @@ -29,8 +29,12 @@ namespace PlexRequests.Core public class CacheKeys { public const string TvDbToken = "TheTvDbApiToken"; + public const string SonarrQualityProfiles = "SonarrQualityProfiles"; + public const string SonarrQueued = "SonarrQueued"; + public const string SickRageQualityProfiles = "SickRageQualityProfiles"; + public const string SickRageQueued = "SickRageQueued"; public const string CouchPotatoQualityProfiles = "CouchPotatoQualityProfiles"; public const string CouchPotatoQueued = "CouchPotatoQueued"; diff --git a/PlexRequests.Services/Interfaces/ISickRageCacher.cs b/PlexRequests.Services/Interfaces/ISickRageCacher.cs new file mode 100644 index 000000000..a42d2a1e4 --- /dev/null +++ b/PlexRequests.Services/Interfaces/ISickRageCacher.cs @@ -0,0 +1,8 @@ +namespace PlexRequests.Services.Interfaces +{ + public interface ISickRageCacher + { + void Queued(long check); + int[] QueuedIds(); + } +} diff --git a/PlexRequests.Services/Interfaces/ISonarrCacher.cs b/PlexRequests.Services/Interfaces/ISonarrCacher.cs new file mode 100644 index 000000000..590666e07 --- /dev/null +++ b/PlexRequests.Services/Interfaces/ISonarrCacher.cs @@ -0,0 +1,8 @@ +namespace PlexRequests.Services.Interfaces +{ + public interface ISonarrCacher + { + void Queued(long check); + int[] QueuedIds(); + } +} diff --git a/PlexRequests.Services/MediaCacheService.cs b/PlexRequests.Services/MediaCacheService.cs index ab6134364..7633fc97f 100644 --- a/PlexRequests.Services/MediaCacheService.cs +++ b/PlexRequests.Services/MediaCacheService.cs @@ -55,6 +55,8 @@ namespace PlexRequests.Services ConfigurationReader = new ConfigurationReader(); CpCacher = new CouchPotatoCacher(new SettingsServiceV2(repo), new CouchPotatoApi(), memCache); + SonarrCacher = new SonarrCacher(new SettingsServiceV2(repo), new SonarrApi(), memCache); + SickRageCacher = new SickRageCacher(new SettingsServiceV2(repo), new SickrageApi(), memCache); HostingEnvironment.RegisterObject(this); } @@ -62,6 +64,8 @@ namespace PlexRequests.Services private IConfigurationReader ConfigurationReader { get; } private ICouchPotatoCacher CpCacher { get; } + private ISonarrCacher SonarrCacher { get; } + private ISickRageCacher SickRageCacher { get; } private IDisposable UpdateSubscription { get; set; } public void Start(Configuration c) @@ -69,7 +73,11 @@ namespace PlexRequests.Services UpdateSubscription?.Dispose(); Task.Factory.StartNew(() => CpCacher.Queued(-1)); + Task.Factory.StartNew(() => SonarrCacher.Queued(-1)); + Task.Factory.StartNew(() => SickRageCacher.Queued(-1)); UpdateSubscription = Observable.Interval(c.Intervals.Notification).Subscribe(CpCacher.Queued); + UpdateSubscription = Observable.Interval(c.Intervals.Notification).Subscribe(SonarrCacher.Queued); + UpdateSubscription = Observable.Interval(c.Intervals.Notification).Subscribe(SickRageCacher.Queued); } public void Execute() diff --git a/PlexRequests.Services/PlexRequests.Services.csproj b/PlexRequests.Services/PlexRequests.Services.csproj index 9642cfed5..bcdb54ab0 100644 --- a/PlexRequests.Services/PlexRequests.Services.csproj +++ b/PlexRequests.Services/PlexRequests.Services.csproj @@ -84,6 +84,10 @@ + + + + diff --git a/PlexRequests.Services/SickRageCacher.cs b/PlexRequests.Services/SickRageCacher.cs new file mode 100644 index 000000000..277b19645 --- /dev/null +++ b/PlexRequests.Services/SickRageCacher.cs @@ -0,0 +1,78 @@ +#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; +using NLog; + +using PlexRequests.Api.Interfaces; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Helpers; +using PlexRequests.Services.Interfaces; +using PlexRequests.Api.Models.Movie; +using System.Linq; +using PlexRequests.Api.Models.SickRage; + +namespace PlexRequests.Services +{ + public class SickRageCacher : ISickRageCacher + { + public SickRageCacher(ISettingsService srSettings, ISickRageApi srApi, ICacheProvider cache) + { + SrSettings = srSettings; + SrApi = srApi; + Cache = cache; + } + + private ISettingsService SrSettings { get; } + private ICacheProvider Cache { get; } + private ISickRageApi SrApi { get; } + + private static Logger Log = LogManager.GetCurrentClassLogger(); + + public void Queued(long check) + { + Log.Trace("This is check no. {0}", check); + Log.Trace("Getting the settings"); + + var settings = SrSettings.GetSettings(); + if (settings.Enabled) + { + Log.Trace("Getting all shows from SickRage"); + var movies = SrApi.GetShows(settings.ApiKey, settings.FullUri); + Cache.Set(CacheKeys.SickRageQueued, movies, 10); + } + } + + // we do not want to set here... + public int[] QueuedIds() + { + var tv = Cache.Get(CacheKeys.SickRageQueued); + return new int[] { }; //tv != null ? tv.Select(x => x.info.tmdb_id).ToArray() : new int[] { }; // TODO: return the array of tvdb IDs from SR + } + } +} \ No newline at end of file diff --git a/PlexRequests.Services/SonarrCacher.cs b/PlexRequests.Services/SonarrCacher.cs new file mode 100644 index 000000000..018db93c0 --- /dev/null +++ b/PlexRequests.Services/SonarrCacher.cs @@ -0,0 +1,77 @@ +#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 NLog; + +using PlexRequests.Api.Interfaces; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Helpers; +using PlexRequests.Services.Interfaces; +using System.Linq; +using System.Collections.Generic; +using PlexRequests.Api.Models.Sonarr; + +namespace PlexRequests.Services +{ + public class SonarrCacher : ISonarrCacher + { + public SonarrCacher(ISettingsService sonarrSettings, ISonarrApi sonarrApi, ICacheProvider cache) + { + SonarrSettings = sonarrSettings; + SonarrApi = sonarrApi; + Cache = cache; + } + + private ISettingsService SonarrSettings { get; } + private ICacheProvider Cache { get; } + private ISonarrApi SonarrApi { get; } + + private static Logger Log = LogManager.GetCurrentClassLogger(); + + public void Queued(long check) + { + Log.Trace("This is check no. {0}", check); + Log.Trace("Getting the settings"); + + var settings = SonarrSettings.GetSettings(); + if (settings.Enabled) + { + Log.Trace("Getting all tv series from Sonarr"); + var series = SonarrApi.GetSeries(settings.ApiKey, settings.FullUri); + Cache.Set(CacheKeys.SonarrQueued, series, 10); + } + } + + // we do not want to set here... + public int[] QueuedIds() + { + var series = Cache.Get>(CacheKeys.SonarrQueued); + return series != null ? series.Select(x => x.tvdbId).ToArray() : new int[] { }; + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs index b05b71019..e50300afa 100644 --- a/PlexRequests.UI/Bootstrapper.cs +++ b/PlexRequests.UI/Bootstrapper.cs @@ -89,6 +89,8 @@ namespace PlexRequests.UI // Services container.Register(); container.Register(); + container.Register(); + container.Register(); container.Register(); container.Register(); diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index 959571a13..fc39cc91f 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -61,7 +61,8 @@ namespace PlexRequests.UI.Modules ISettingsService prSettings, IAvailabilityChecker checker, IRequestService request, ISonarrApi sonarrApi, ISettingsService sonarrSettings, ISettingsService sickRageService, ICouchPotatoApi cpApi, ISickRageApi srApi, - INotificationService notify, IMusicBrainzApi mbApi, IHeadphonesApi hpApi, ISettingsService hpService, ICouchPotatoCacher cpCacher) : base("search") + INotificationService notify, IMusicBrainzApi mbApi, IHeadphonesApi hpApi, ISettingsService hpService, + ICouchPotatoCacher cpCacher, ISonarrCacher sonarrCacher, ISickRageCacher sickRageCacher) : base("search") { CpService = cpSettings; PrService = prSettings; @@ -70,6 +71,8 @@ namespace PlexRequests.UI.Modules Cache = cache; Checker = checker; CpCacher = cpCacher; + SonarrCacher = sonarrCacher; + SickRageCacher = sickRageCacher; RequestService = request; SonarrApi = sonarrApi; SonarrService = sonarrSettings; @@ -111,6 +114,8 @@ namespace PlexRequests.UI.Modules private ISettingsService HeadphonesService { get; } private IAvailabilityChecker Checker { get; } private ICouchPotatoCacher CpCacher { get; } + private ISonarrCacher SonarrCacher { get; } + private ISickRageCacher SickRageCacher { get; } private IMusicBrainzApi MusicBrainzApi { get; } private IHeadphonesApi HeadphonesApi { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); @@ -277,6 +282,8 @@ namespace PlexRequests.UI.Modules return Response.AsJson(""); } + int[] sonarrCached = SonarrCacher.QueuedIds(); + int[] sickRageCache = SickRageCacher.QueuedIds(); // consider just merging sonarr/sickrage arrays var viewTv = new List(); foreach (var t in apiTv) @@ -299,13 +306,22 @@ namespace PlexRequests.UI.Modules Status = t.show.status }; - if (t.show.externals.thetvdb != null && dbTv.ContainsKey((int)t.show.externals.thetvdb)) + if (t.show.externals.thetvdb != null) { - var dbt = dbTv[(int)t.show.externals.thetvdb]; + int tvdbid = (int)t.show.externals.thetvdb; - viewT.Requested = true; - viewT.Approved = dbt.Approved; - viewT.Available = dbt.Available; + if (dbTv.ContainsKey(tvdbid)) + { + var dbt = dbTv[tvdbid]; + + viewT.Requested = true; + viewT.Approved = dbt.Approved; + viewT.Available = dbt.Available; + } + else if (sonarrCached.Contains(tvdbid) || sickRageCache.Contains(tvdbid)) // compare to the sonarr/sickrage db + { + viewT.Requested = true; + } } viewTv.Add(viewT);