From 6ed7df2c213fbade45f629446b43e0e565feb4aa Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Thu, 7 Apr 2016 21:45:05 -0500 Subject: [PATCH] cache the couchpotato wanted list, update it on an interval, and use it to determine if a movie has been queued already --- .../ICouchPotatoApi.cs | 1 + .../Movie/CouchPotatoAdd.cs | 35 ++++++-- .../Movie/CouchPotatoMovies.cs | 12 +++ .../PlexRequests.Api.Models.csproj | 1 + PlexRequests.Api/CouchPotatoApi.cs | 11 +++ PlexRequests.Core/CacheKeys.cs | 2 + PlexRequests.Services/CouchPotatoCacher.cs | 77 ++++++++++++++++ .../Interfaces/ICouchPotatoCacher.cs | 8 ++ PlexRequests.Services/MediaCacheService.cs | 89 +++++++++++++++++++ PlexRequests.UI/Bootstrapper.cs | 2 + PlexRequests.UI/Jobs/MediaCacheRegistry.cs | 41 +++++++++ PlexRequests.UI/Modules/SearchModule.cs | 14 ++- PlexRequests.UI/PlexRequests.UI.csproj | 1 + 13 files changed, 283 insertions(+), 11 deletions(-) create mode 100644 PlexRequests.Api.Models/Movie/CouchPotatoMovies.cs create mode 100644 PlexRequests.Services/CouchPotatoCacher.cs create mode 100644 PlexRequests.Services/Interfaces/ICouchPotatoCacher.cs create mode 100644 PlexRequests.Services/MediaCacheService.cs create mode 100644 PlexRequests.UI/Jobs/MediaCacheRegistry.cs diff --git a/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs b/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs index 288f09d67..0e018e6a8 100644 --- a/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs +++ b/PlexRequests.Api.Interfaces/ICouchPotatoApi.cs @@ -36,5 +36,6 @@ namespace PlexRequests.Api.Interfaces bool AddMovie(string imdbid, string apiKey, string title, Uri baseUrl, string profileID = default(string)); CouchPotatoStatus GetStatus(Uri url, string apiKey); CouchPotatoProfiles GetProfiles(Uri url, string apiKey); + CouchPotatoMovies GetMovies(Uri baseUrl, string apiKey, string[] status); } } \ No newline at end of file diff --git a/PlexRequests.Api.Models/Movie/CouchPotatoAdd.cs b/PlexRequests.Api.Models/Movie/CouchPotatoAdd.cs index 5a2e228b9..adad93c74 100644 --- a/PlexRequests.Api.Models/Movie/CouchPotatoAdd.cs +++ b/PlexRequests.Api.Models/Movie/CouchPotatoAdd.cs @@ -14,7 +14,7 @@ namespace PlexRequests.Api.Models.Movie } public class Rating { - public List imdb { get; set; } + public List imdb { get; set; } } @@ -23,15 +23,15 @@ namespace PlexRequests.Api.Models.Movie { public List disc_art { get; set; } public List poster { get; set; } + public List backdrop { get; set; } public List extra_thumbs { get; set; } public List poster_original { get; set; } - public List landscape { get; set; } - public string[] actors { get; set; } + public List actors { get; set; } public List backdrop_original { get; set; } public List clear_art { get; set; } public List logo { get; set; } public List banner { get; set; } - public List backdrop { get; set; } + public List landscape { get; set; } public List extra_fanart { get; set; } } @@ -42,16 +42,17 @@ namespace PlexRequests.Api.Models.Movie public int tmdb_id { get; set; } public string plot { get; set; } public string tagline { get; set; } + public Release_Date release_date { get; set; } + public int year { get; set; } public string original_title { get; set; } - public string[] actor_roles { get; set; } + public List actor_roles { get; set; } public bool via_imdb { get; set; } - public string mpaa { get; set; } - public bool via_tmdb { get; set; } + public Images images { get; set; } public List directors { get; set; } public List titles { get; set; } public string imdb { get; set; } - public int year { get; set; } - public Images images { get; set; } + public string mpaa { get; set; } + public bool via_tmdb { get; set; } public List actors { get; set; } public List writers { get; set; } public int runtime { get; set; } @@ -59,6 +60,19 @@ namespace PlexRequests.Api.Models.Movie public string released { get; set; } } + public class Release_Date + { + public int dvd { get; set; } + public int expires { get; set; } + public int theater { get; set; } + public bool bluray { get; set; } + } + + public class Files + { + public List image_poster { get; set; } + } + public class Identifiers { public string imdb { get; set; } @@ -74,8 +88,11 @@ namespace PlexRequests.Api.Models.Movie public string _rev { get; set; } public string profile_id { get; set; } public string _id { get; set; } + public List tags { get; set; } + public int last_edit { get; set; } public object category_id { get; set; } public string type { get; set; } + public Files files { get; set; } public Identifiers identifiers { get; set; } } diff --git a/PlexRequests.Api.Models/Movie/CouchPotatoMovies.cs b/PlexRequests.Api.Models/Movie/CouchPotatoMovies.cs new file mode 100644 index 000000000..33399179c --- /dev/null +++ b/PlexRequests.Api.Models/Movie/CouchPotatoMovies.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace PlexRequests.Api.Models.Movie +{ + public class CouchPotatoMovies + { + public List movies { get; set; } + public int total { get; set; } + public bool success { get; set; } + public bool empty { get; set; } + } +} diff --git a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj index 33b154211..ec15e83d1 100644 --- a/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj +++ b/PlexRequests.Api.Models/PlexRequests.Api.Models.csproj @@ -46,6 +46,7 @@ + diff --git a/PlexRequests.Api/CouchPotatoApi.cs b/PlexRequests.Api/CouchPotatoApi.cs index 7e660a38d..88cc07075 100644 --- a/PlexRequests.Api/CouchPotatoApi.cs +++ b/PlexRequests.Api/CouchPotatoApi.cs @@ -115,5 +115,16 @@ namespace PlexRequests.Api return Api.Execute(request, url); } + + public CouchPotatoMovies GetMovies(Uri baseUrl, string apiKey, string[] status) + { + RestRequest request; + request = new RestRequest { Resource = "/api/{apikey}/movie.list?status={status}" }; + + request.AddUrlSegment("apikey", apiKey); + request.AddUrlSegment("status", string.Join(",", status)); + + return Api.Execute(request, baseUrl); + } } } \ No newline at end of file diff --git a/PlexRequests.Core/CacheKeys.cs b/PlexRequests.Core/CacheKeys.cs index a40291b91..dfa07891c 100644 --- a/PlexRequests.Core/CacheKeys.cs +++ b/PlexRequests.Core/CacheKeys.cs @@ -31,6 +31,8 @@ namespace PlexRequests.Core public const string TvDbToken = "TheTvDbApiToken"; public const string SonarrQualityProfiles = "SonarrQualityProfiles"; public const string SickRageQualityProfiles = "SickRageQualityProfiles"; + public const string CouchPotatoQualityProfiles = "CouchPotatoQualityProfiles"; + public const string CouchPotatoQueued = "CouchPotatoQueued"; } } \ No newline at end of file diff --git a/PlexRequests.Services/CouchPotatoCacher.cs b/PlexRequests.Services/CouchPotatoCacher.cs new file mode 100644 index 000000000..557a29179 --- /dev/null +++ b/PlexRequests.Services/CouchPotatoCacher.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 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; + +namespace PlexRequests.Services +{ + public class CouchPotatoCacher : ICouchPotatoCacher + { + public CouchPotatoCacher(ISettingsService cpSettings, ICouchPotatoApi cpApi, ICacheProvider cache) + { + CpSettings = cpSettings; + CpApi = cpApi; + Cache = cache; + } + + private ISettingsService CpSettings { get; } + private ICacheProvider Cache { get; } + private ICouchPotatoApi CpApi { 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 = CpSettings.GetSettings(); + if (settings.Enabled) + { + Log.Trace("Getting all movies from CouchPotato"); + var movies = CpApi.GetMovies(settings.FullUri, settings.ApiKey, new[] { "active" }); + Cache.Set(CacheKeys.CouchPotatoQueued, movies, 10); + } + } + + // we do not want to set here... + public int[] QueuedIds() + { + var movies = Cache.Get(CacheKeys.CouchPotatoQueued); + return movies != null ? movies.movies.Select(x => x.info.tmdb_id).ToArray() : new int[] { }; + } + } +} \ No newline at end of file diff --git a/PlexRequests.Services/Interfaces/ICouchPotatoCacher.cs b/PlexRequests.Services/Interfaces/ICouchPotatoCacher.cs new file mode 100644 index 000000000..4da6fa852 --- /dev/null +++ b/PlexRequests.Services/Interfaces/ICouchPotatoCacher.cs @@ -0,0 +1,8 @@ +namespace PlexRequests.Services.Interfaces +{ + public interface ICouchPotatoCacher + { + void Queued(long check); + int[] QueuedIds(); + } +} diff --git a/PlexRequests.Services/MediaCacheService.cs b/PlexRequests.Services/MediaCacheService.cs new file mode 100644 index 000000000..1517234d3 --- /dev/null +++ b/PlexRequests.Services/MediaCacheService.cs @@ -0,0 +1,89 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: AvailabilityUpdateService.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.Reactive.Linq; +using System.Web.Hosting; + +using FluentScheduler; + +using Mono.Data.Sqlite; + +using NLog; + +using PlexRequests.Api; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Helpers; +using PlexRequests.Services.Interfaces; +using PlexRequests.Store; +using PlexRequests.Store.Repository; + +namespace PlexRequests.Services +{ + public class MediaCacheService : ITask, IRegisteredObject, IAvailabilityUpdateService + { + public MediaCacheService() + { + var memCache = new MemoryCacheProvider(); + var dbConfig = new DbConfiguration(new SqliteFactory()); + var repo = new SettingsJsonRepository(dbConfig, memCache); + + ConfigurationReader = new ConfigurationReader(); + CpCacher = new CouchPotatoCacher(new SettingsServiceV2(repo), new CouchPotatoApi(), memCache); + HostingEnvironment.RegisterObject(this); + } + + private static Logger Log = LogManager.GetCurrentClassLogger(); + + private IConfigurationReader ConfigurationReader { get; } + private ICouchPotatoCacher CpCacher { get; } + private IDisposable UpdateSubscription { get; set; } + + public void Start(Configuration c) + { + UpdateSubscription?.Dispose(); + + CpCacher.Queued(-1); + UpdateSubscription = Observable.Interval(c.Intervals.Notification).Subscribe(CpCacher.Queued); + } + + public void Execute() + { + Start(ConfigurationReader.Read()); + } + + public void Stop(bool immediate) + { + HostingEnvironment.UnregisterObject(this); + } + } + + public interface ICouchPotatoCacheService + { + void Start(Configuration c); + } +} diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs index a4e13f18b..a3a8bc723 100644 --- a/PlexRequests.UI/Bootstrapper.cs +++ b/PlexRequests.UI/Bootstrapper.cs @@ -85,6 +85,7 @@ namespace PlexRequests.UI // Services container.Register(); + container.Register(); container.Register(); container.Register(); @@ -106,6 +107,7 @@ namespace PlexRequests.UI TaskManager.TaskFactory = new PlexTaskFactory(); TaskManager.Initialize(new PlexRegistry()); + TaskManager.Initialize(new MediaCacheRegistry()); } protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) diff --git a/PlexRequests.UI/Jobs/MediaCacheRegistry.cs b/PlexRequests.UI/Jobs/MediaCacheRegistry.cs new file mode 100644 index 000000000..3b4b2b68c --- /dev/null +++ b/PlexRequests.UI/Jobs/MediaCacheRegistry.cs @@ -0,0 +1,41 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: PlexRegistry.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 FluentScheduler; + +using PlexRequests.Services; + +namespace PlexRequests.UI.Jobs +{ + public class MediaCacheRegistry : Registry + { + public MediaCacheRegistry() + { + Schedule().ToRunNow(); + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index 9511034c1..cb2be3625 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -61,7 +61,7 @@ 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) : base("search") + INotificationService notify, IMusicBrainzApi mbApi, IHeadphonesApi hpApi, ISettingsService hpService, ICouchPotatoCacher cpCacher) : base("search") { CpService = cpSettings; PrService = prSettings; @@ -69,6 +69,7 @@ namespace PlexRequests.UI.Modules TvApi = new TheTvDbApi(); Cache = cache; Checker = checker; + CpCacher = cpCacher; RequestService = request; SonarrApi = sonarrApi; SonarrService = sonarrSettings; @@ -109,6 +110,7 @@ namespace PlexRequests.UI.Modules private ISettingsService SickRageService { get; } private ISettingsService HeadphonesService { get; } private IAvailabilityChecker Checker { get; } + private ICouchPotatoCacher CpCacher { get; } private IMusicBrainzApi MusicBrainzApi { get; } private IHeadphonesApi HeadphonesApi { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); @@ -150,6 +152,8 @@ namespace PlexRequests.UI.Modules private Response ProcessMovies(MovieSearchType searchType, string searchTerm) { List taskList = new List(); + var z = CpService.GetSettings(); + CouchPotatoApi.GetMovies(z.FullUri, z.ApiKey, new[] { "active" }); List apiMovies = new List(); taskList.Add(Task.Factory.StartNew>(() => @@ -198,6 +202,8 @@ namespace PlexRequests.UI.Modules Task.WaitAll(taskList.ToArray()); + int[] cpCached = CpCacher.QueuedIds(); + List viewMovies = new List(); foreach (MovieResult movie in apiMovies) { @@ -219,7 +225,7 @@ namespace PlexRequests.UI.Modules VoteCount = movie.VoteCount }; - if (dbMovies.ContainsKey(movie.Id)) + if (dbMovies.ContainsKey(movie.Id)) // compare to the requests db { var dbm = dbMovies[movie.Id]; @@ -227,6 +233,10 @@ namespace PlexRequests.UI.Modules viewMovie.Approved = dbm.Approved; viewMovie.Available = dbm.Available; } + else if (cpCached.Contains(movie.Id)) // compare to the couchpotato db + { + viewMovie.Requested = true; + } viewMovies.Add(viewMovie); } diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index 7d4cbfb9a..c3325ff7d 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -168,6 +168,7 @@ +