cache injection, error handling and logging on startup, etc

pull/140/head
Drewster727 9 years ago
parent 2ddb949178
commit 7593d3a7e9

@ -1,116 +1,116 @@
#region Copyright #region Copyright
// /************************************************************************ // /************************************************************************
// Copyright (c) 2016 Jamie Rees // Copyright (c) 2016 Jamie Rees
// File: MusicBrainzApi.cs // File: MusicBrainzApi.cs
// Created By: Jamie Rees // Created By: Jamie Rees
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the // a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including // "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, // without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to // distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to // permit persons to whom the Software is furnished to do so, subject to
// the following conditions: // the following conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System; using System;
using Newtonsoft.Json; using Newtonsoft.Json;
using NLog; using NLog;
using PlexRequests.Api.Interfaces; using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models.Music; using PlexRequests.Api.Models.Music;
using RestSharp; using RestSharp;
namespace PlexRequests.Api namespace PlexRequests.Api
{ {
public class MusicBrainzApi : IMusicBrainzApi public class MusicBrainzApi : IMusicBrainzApi
{ {
public MusicBrainzApi() public MusicBrainzApi()
{ {
Api = new ApiRequest(); Api = new ApiRequest();
} }
private ApiRequest Api { get; } private ApiRequest Api { get; }
private static readonly Logger Log = LogManager.GetCurrentClassLogger(); private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private readonly Uri BaseUri = new Uri("http://musicbrainz.org/ws/2/"); private readonly Uri BaseUri = new Uri("http://musicbrainz.org/ws/2/");
public MusicBrainzSearchResults SearchAlbum(string searchTerm) public MusicBrainzSearchResults SearchAlbum(string searchTerm)
{ {
Log.Trace("Searching for album: {0}", searchTerm); Log.Trace("Searching for album: {0}", searchTerm);
var request = new RestRequest var request = new RestRequest
{ {
Resource = "release/?query={searchTerm}&fmt=json", Resource = "release/?query={searchTerm}&fmt=json",
Method = Method.GET Method = Method.GET
}; };
request.AddUrlSegment("searchTerm", searchTerm); request.AddUrlSegment("searchTerm", searchTerm);
try try
{ {
return Api.ExecuteJson<MusicBrainzSearchResults>(request, BaseUri); return Api.ExecuteJson<MusicBrainzSearchResults>(request, BaseUri);
} }
catch (JsonSerializationException jse) catch (JsonSerializationException jse)
{ {
Log.Warn(jse); Log.Warn(jse);
return new MusicBrainzSearchResults(); // If there is no matching result we do not get returned a JSON string, it just returns "false". return new MusicBrainzSearchResults(); // If there is no matching result we do not get returned a JSON string, it just returns "false".
} }
} }
public MusicBrainzReleaseInfo GetAlbum(string releaseId) public MusicBrainzReleaseInfo GetAlbum(string releaseId)
{ {
Log.Trace("Getting album: {0}", releaseId); Log.Trace("Getting album: {0}", releaseId);
var request = new RestRequest var request = new RestRequest
{ {
Resource = "release/{albumId}", Resource = "release/{albumId}",
Method = Method.GET Method = Method.GET
}; };
request.AddUrlSegment("albumId", releaseId); request.AddUrlSegment("albumId", releaseId);
request.AddQueryParameter("fmt", "json"); request.AddQueryParameter("fmt", "json");
request.AddQueryParameter("inc", "artists"); request.AddQueryParameter("inc", "artists");
try try
{ {
return Api.ExecuteJson<MusicBrainzReleaseInfo>(request, BaseUri); return Api.ExecuteJson<MusicBrainzReleaseInfo>(request, BaseUri);
} }
catch (JsonSerializationException jse) catch (JsonSerializationException jse)
{ {
Log.Warn(jse); Log.Warn(jse);
return new MusicBrainzReleaseInfo(); // If there is no matching result we do not get returned a JSON string, it just returns "false". return new MusicBrainzReleaseInfo(); // If there is no matching result we do not get returned a JSON string, it just returns "false".
} }
} }
public MusicBrainzCoverArt GetCoverArt(string releaseId) public MusicBrainzCoverArt GetCoverArt(string releaseId)
{ {
Log.Trace("Getting cover art for release: {0}", releaseId); Log.Trace("Getting cover art for release: {0}", releaseId);
var request = new RestRequest var request = new RestRequest
{ {
Resource = "release/{releaseId}", Resource = "release/{releaseId}",
Method = Method.GET Method = Method.GET
}; };
request.AddUrlSegment("releaseId", releaseId); request.AddUrlSegment("releaseId", releaseId);
try try
{ {
return Api.Execute<MusicBrainzCoverArt>(request, new Uri("http://coverartarchive.org/")); return Api.Execute<MusicBrainzCoverArt>(request, new Uri("http://coverartarchive.org/"));
} }
catch (Exception e) catch (Exception e)
{ {
Log.Warn(e); Log.Warn(e);
return new MusicBrainzCoverArt(); // If there is no matching result we do not get returned a JSON string, it just returns "false". return new MusicBrainzCoverArt(); // If there is no matching result we do not get returned a JSON string, it just returns "false".
} }
} }
} }
} }

@ -121,30 +121,45 @@ namespace PlexRequests.Core
private async void CacheSonarrQualityProfiles(MemoryCacheProvider cacheProvider) private async void CacheSonarrQualityProfiles(MemoryCacheProvider cacheProvider)
{ {
var sonarrSettingsService = new SettingsServiceV2<SonarrSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); try
var sonarrSettings = sonarrSettingsService.GetSettings(); {
if (sonarrSettings.Enabled) { Log.Info("Executing GetSettings call to Sonarr for quality profiles");
cacheProvider.GetOrSet(CacheKeys.SonarrQualityProfiles, () => var sonarrSettingsService = new SettingsServiceV2<SonarrSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider()));
var sonarrSettings = sonarrSettingsService.GetSettings();
if (sonarrSettings.Enabled)
{ {
Log.Info("Begin executing GetProfiles call to Sonarr for quality profiles");
SonarrApi sonarrApi = new SonarrApi(); SonarrApi sonarrApi = new SonarrApi();
return sonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri); var profiles = sonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri);
cacheProvider.Set(CacheKeys.SonarrQualityProfiles, profiles);
}); Log.Info("Finished executing GetProfiles call to Sonarr for quality profiles");
}
}
catch (Exception ex)
{
Log.Error("Failed to cache Sonarr quality profiles!", ex);
} }
} }
private async void CacheCouchPotatoQualityProfiles(MemoryCacheProvider cacheProvider) private async void CacheCouchPotatoQualityProfiles(MemoryCacheProvider cacheProvider)
{ {
var cpSettingsService = new SettingsServiceV2<CouchPotatoSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); try
var cpSettings = cpSettingsService.GetSettings();
if (cpSettings.Enabled)
{ {
cacheProvider.GetOrSet(CacheKeys.CouchPotatoQualityProfiles, () => Log.Info("Executing GetSettings call to CouchPotato for quality profiles");
var cpSettingsService = new SettingsServiceV2<CouchPotatoSettings>(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider()));
var cpSettings = cpSettingsService.GetSettings();
if (cpSettings.Enabled)
{ {
Log.Info("Begin executing GetProfiles call to CouchPotato for quality profiles");
CouchPotatoApi cpApi = new CouchPotatoApi(); CouchPotatoApi cpApi = new CouchPotatoApi();
return cpApi.GetProfiles(cpSettings.FullUri, cpSettings.ApiKey); var profiles = cpApi.GetProfiles(cpSettings.FullUri, cpSettings.ApiKey);
cacheProvider.Set(CacheKeys.CouchPotatoQualityProfiles, profiles);
}); Log.Info("Finished executing GetProfiles call to CouchPotato for quality profiles");
}
}
catch (Exception ex)
{
Log.Error("Failed to cache CouchPotato quality profiles!", ex);
} }
} }

@ -55,7 +55,7 @@ namespace PlexRequests.Helpers
/// <param name="key">The key.</param> /// <param name="key">The key.</param>
/// <param name="data">The object we want to store.</param> /// <param name="data">The object we want to store.</param>
/// <param name="cacheTime">The amount of time we want to cache the object.</param> /// <param name="cacheTime">The amount of time we want to cache the object.</param>
void Set(string key, object data, int cacheTime); void Set(string key, object data, int cacheTime = 20);
/// <summary> /// <summary>
/// Removes the specified object from the cache. /// Removes the specified object from the cache.

@ -76,6 +76,7 @@ namespace PlexRequests.UI.Modules
private ICouchPotatoApi CpApi { get; } private ICouchPotatoApi CpApi { get; }
private IRepository<LogEntity> LogsRepo { get; } private IRepository<LogEntity> LogsRepo { get; }
private INotificationService NotificationService { get; } private INotificationService NotificationService { get; }
private ICacheProvider Cache { get; }
private static Logger Log = LogManager.GetCurrentClassLogger(); private static Logger Log = LogManager.GetCurrentClassLogger();
public AdminModule(ISettingsService<PlexRequestSettings> prService, public AdminModule(ISettingsService<PlexRequestSettings> prService,
@ -94,7 +95,8 @@ namespace PlexRequests.UI.Modules
IPushoverApi pushoverApi, IPushoverApi pushoverApi,
IRepository<LogEntity> logsRepo, IRepository<LogEntity> logsRepo,
INotificationService notify, INotificationService notify,
ISettingsService<HeadphonesSettings> headphones) : base("admin") ISettingsService<HeadphonesSettings> headphones,
ICacheProvider cache) : base("admin")
{ {
PrService = prService; PrService = prService;
CpService = cpService; CpService = cpService;
@ -113,6 +115,7 @@ namespace PlexRequests.UI.Modules
PushoverApi = pushoverApi; PushoverApi = pushoverApi;
NotificationService = notify; NotificationService = notify;
HeadphonesService = headphones; HeadphonesService = headphones;
Cache = cache;
#if !DEBUG #if !DEBUG
this.RequiresAuthentication(); this.RequiresAuthentication();
@ -377,8 +380,7 @@ namespace PlexRequests.UI.Modules
// set the cache // set the cache
if (profiles != null) if (profiles != null)
{ {
var cache = new MemoryCacheProvider(); Cache.Set(CacheKeys.SonarrQualityProfiles, profiles);
cache.Set(CacheKeys.SonarrQualityProfiles, profiles);
} }
return Response.AsJson(profiles); return Response.AsJson(profiles);
@ -592,8 +594,7 @@ namespace PlexRequests.UI.Modules
// set the cache // set the cache
if (profiles != null) if (profiles != null)
{ {
var cache = new MemoryCacheProvider(); Cache.Set(CacheKeys.CouchPotatoQualityProfiles, profiles);
cache.Set(CacheKeys.CouchPotatoQualityProfiles, profiles);
} }
return Response.AsJson(profiles); return Response.AsJson(profiles);

@ -59,7 +59,8 @@ namespace PlexRequests.UI.Modules
ISettingsService<CouchPotatoSettings> cpSettings, ISettingsService<CouchPotatoSettings> cpSettings,
ICouchPotatoApi cpApi, ICouchPotatoApi cpApi,
ISonarrApi sonarrApi, ISonarrApi sonarrApi,
ISickRageApi sickRageApi) : base("requests") ISickRageApi sickRageApi,
ICacheProvider cache) : base("requests")
{ {
Service = service; Service = service;
PrSettings = prSettings; PrSettings = prSettings;
@ -71,6 +72,7 @@ namespace PlexRequests.UI.Modules
SonarrApi = sonarrApi; SonarrApi = sonarrApi;
SickRageApi = sickRageApi; SickRageApi = sickRageApi;
CpApi = cpApi; CpApi = cpApi;
Cache = cache;
Get["/"] = _ => LoadRequests(); Get["/"] = _ => LoadRequests();
Get["/movies"] = _ => GetMovies(); Get["/movies"] = _ => GetMovies();
@ -96,6 +98,7 @@ namespace PlexRequests.UI.Modules
private ISonarrApi SonarrApi { get; } private ISonarrApi SonarrApi { get; }
private ISickRageApi SickRageApi { get; } private ISickRageApi SickRageApi { get; }
private ICouchPotatoApi CpApi { get; } private ICouchPotatoApi CpApi { get; }
private ICacheProvider Cache { get; }
private Negotiator LoadRequests() private Negotiator LoadRequests()
{ {
@ -126,7 +129,6 @@ namespace PlexRequests.UI.Modules
})); }));
var mc = new MemoryCacheProvider();
List<QualityModel> qualities = new List<QualityModel>(); List<QualityModel> qualities = new List<QualityModel>();
if (isAdmin) if (isAdmin)
@ -136,7 +138,7 @@ namespace PlexRequests.UI.Modules
{ {
taskList.Add(Task.Factory.StartNew(() => taskList.Add(Task.Factory.StartNew(() =>
{ {
return mc.GetOrSet(CacheKeys.CouchPotatoQualityProfiles, () => return Cache.GetOrSet(CacheKeys.CouchPotatoQualityProfiles, () =>
{ {
return CpApi.GetProfiles(cpSettings.FullUri, cpSettings.ApiKey); // TODO: cache this! return CpApi.GetProfiles(cpSettings.FullUri, cpSettings.ApiKey); // TODO: cache this!
}); });
@ -202,7 +204,6 @@ namespace PlexRequests.UI.Modules
} }
})); }));
var mc = new MemoryCacheProvider();
List<QualityModel> qualities = new List<QualityModel>(); List<QualityModel> qualities = new List<QualityModel>();
if (isAdmin) if (isAdmin)
{ {
@ -211,7 +212,7 @@ namespace PlexRequests.UI.Modules
{ {
taskList.Add(Task.Factory.StartNew(() => taskList.Add(Task.Factory.StartNew(() =>
{ {
return mc.GetOrSet(CacheKeys.SonarrQualityProfiles, () => return Cache.GetOrSet(CacheKeys.SonarrQualityProfiles, () =>
{ {
return SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri); // TODO: cache this! return SonarrApi.GetProfiles(sonarrSettings.ApiKey, sonarrSettings.FullUri); // TODO: cache this!

@ -268,7 +268,7 @@ namespace PlexRequests.UI.Modules
}; };
Log.Trace(settings.DumpJson()); Log.Trace(settings.DumpJson());
if (IsAdmin || !settings.RequireMovieApproval || settings.ApprovalWhiteList.Any(x => x.Equals(Username, StringComparison.OrdinalIgnoreCase))) if (ShouldAutoApprove(RequestType.Movie, settings))
{ {
var cpSettings = CpService.GetSettings(); var cpSettings = CpService.GetSettings();
@ -422,7 +422,7 @@ namespace PlexRequests.UI.Modules
model.SeasonList = seasonsList.ToArray(); model.SeasonList = seasonsList.ToArray();
if (IsAdmin || !settings.RequireTvShowApproval || settings.ApprovalWhiteList.Any(x => x.Equals(Username, StringComparison.OrdinalIgnoreCase))) if (ShouldAutoApprove(RequestType.TvShow, settings))
{ {
var sonarrSettings = SonarrService.GetSettings(); var sonarrSettings = SonarrService.GetSettings();
var sender = new TvSender(SonarrApi, SickrageApi); var sender = new TvSender(SonarrApi, SickrageApi);
@ -537,8 +537,7 @@ namespace PlexRequests.UI.Modules
}; };
if (IsAdmin || !settings.RequireMusicApproval || if (ShouldAutoApprove(RequestType.Album, settings))
settings.ApprovalWhiteList.Any(x => x.Equals(Username, StringComparison.OrdinalIgnoreCase)))
{ {
Log.Debug("We don't require approval OR the user is in the whitelist"); Log.Debug("We don't require approval OR the user is in the whitelist");
var hpSettings = HeadphonesService.GetSettings(); var hpSettings = HeadphonesService.GetSettings();
@ -589,5 +588,24 @@ namespace PlexRequests.UI.Modules
return img; return img;
} }
private bool ShouldAutoApprove(RequestType requestType, PlexRequestSettings prSettings)
{
// if the user is an admin or they are whitelisted, they go ahead and allow auto-approval
if (IsAdmin || prSettings.ApprovalWhiteList.Any(x => x.Equals(Username, StringComparison.OrdinalIgnoreCase))) return true;
// check by request type if the category requires approval or not
switch (requestType)
{
case RequestType.Movie:
return !prSettings.RequireMovieApproval;
case RequestType.TvShow:
return !prSettings.RequireTvShowApproval;
case RequestType.Album:
return !prSettings.RequireMusicApproval;
default:
return false;
}
}
} }
} }

Loading…
Cancel
Save