diff --git a/src/Ombi.Core/Engine/MovieSearchEngine.cs b/src/Ombi.Core/Engine/MovieSearchEngine.cs index ef3638741..da64e99b6 100644 --- a/src/Ombi.Core/Engine/MovieSearchEngine.cs +++ b/src/Ombi.Core/Engine/MovieSearchEngine.cs @@ -10,9 +10,7 @@ using System.Linq; using System.Security.Principal; using System.Threading.Tasks; using Ombi.Core.Rule.Interfaces; -using StackExchange.Profiling; using Microsoft.Extensions.Caching.Memory; -using Ombi.Api.Trakt; using Ombi.Core.Authentication; using Ombi.Helpers; @@ -55,22 +53,14 @@ namespace Ombi.Core.Engine /// public async Task> Search(string search) { - using (MiniProfiler.Current.Step("Starting Movie Search Engine")) - using (MiniProfiler.Current.Step("Searching Movie")) + var result = await MovieApi.SearchMovie(search); + + if (result != null) { - var result = await MovieApi.SearchMovie(search); - - using (MiniProfiler.Current.Step("Fin API, Transforming")) - { - if (result != null) - { - Logger.LogDebug("Search Result: {result}", result); - return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API - } - } - - return null; + Logger.LogDebug("Search Result: {result}", result); + return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API } + return null; } /// @@ -174,7 +164,7 @@ namespace Ombi.Core.Engine // So set the ImdbId to viewMovie.Id and then set it back afterwards var oldId = viewMovie.Id; viewMovie.CustomId = viewMovie.ImdbId ?? string.Empty; - + await RunSearchRules(viewMovie); viewMovie.Id = oldId; diff --git a/src/Ombi.Core/Engine/TvSearchEngine.cs b/src/Ombi.Core/Engine/TvSearchEngine.cs index cf5d1ef3c..8cfae9506 100644 --- a/src/Ombi.Core/Engine/TvSearchEngine.cs +++ b/src/Ombi.Core/Engine/TvSearchEngine.cs @@ -15,11 +15,7 @@ using System.Linq; using System.Security.Principal; using System.Threading.Tasks; using Ombi.Core.Rule.Interfaces; -using Ombi.Store.Entities.Requests; using Ombi.Store.Repository.Requests; -using Ombi.Store.Entities; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Ombi.Core.Authentication; using Ombi.Helpers; @@ -117,11 +113,7 @@ namespace Ombi.Core.Engine }); } } - - var existingRequests = await GetTvRequests(); - var plexSettings = await PlexSettings.GetSettingsAsync(); - var embySettings = await EmbySettings.GetSettingsAsync(); - return await ProcessResult(mapped, existingRequests, plexSettings, embySettings); + return await ProcessResult(mapped); } public async Task> GetShowInformationTreeNode(int tvdbid) @@ -189,127 +181,21 @@ namespace Ombi.Core.Engine }; } - private async Task> ProcessResults(IEnumerable items) { - var existingRequests = await GetTvRequests(); - - var plexSettings = await PlexSettings.GetSettingsAsync(); - var embySettings = await EmbySettings.GetSettingsAsync(); - var retVal = new List(); foreach (var tvMazeSearch in items) { var viewT = Mapper.Map(tvMazeSearch); - retVal.Add(await ProcessResult(viewT, existingRequests, plexSettings, embySettings)); + retVal.Add(await ProcessResult(viewT)); } return retVal; } - private async Task ProcessResult(SearchTvShowViewModel item, Dictionary existingRequests, PlexSettings plexSettings, EmbySettings embySettings) + private async Task ProcessResult(SearchTvShowViewModel item) { - if (embySettings.Enable) - { - var content = await EmbyContentRepo.Get(item.Id.ToString()); - - if (content != null) - { - item.Available = true; - } - - // Let's go through the episodes now - if (item.SeasonRequests.Any()) - { - var allEpisodes = EmbyContentRepo.GetAllEpisodes().Include(x => x.Series); - foreach (var season in item.SeasonRequests) - { - foreach (var episode in season.Episodes) - { - var epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && item.Id.ToString() == x.Series.ProviderId); - if (epExists != null) - { - episode.Available = true; - } - } - } - } - } - if (plexSettings.Enable) - { - var content = await PlexContentRepo.Get(item.Id.ToString()); - - if (content != null) - { - item.Available = true; - item.PlexUrl = content.Url; - } - // Let's go through the episodes now - if (item.SeasonRequests.Any()) - { - var allEpisodes = PlexContentRepo.GetAllEpisodes(); - foreach (var season in item.SeasonRequests) - { - foreach (var episode in season.Episodes) - { - var epExists = await allEpisodes.FirstOrDefaultAsync(x => - x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && x.Series.ProviderId == item.Id.ToString()); - if (epExists != null) - { - episode.Available = true; - } - } - } - } - } - - if (item.SeasonRequests.Any() && item.SeasonRequests.All(x => x.Episodes.All(e => e.Approved))) - { - item.FullyAvailable = true; - } - - if (item.Id > 0) - { - var tvdbid = item.Id; - if (existingRequests.ContainsKey(tvdbid)) - { - var existingRequest = existingRequests[tvdbid]; - - item.Requested = true; - item.Approved = existingRequest.ChildRequests.Any(x => x.Approved); - - // Let's modify the seasonsrequested to reflect what we have requested... - foreach (var season in item.SeasonRequests) - { - foreach (var existingRequestChildRequest in existingRequest.ChildRequests) - { - // Find the existing request season - var existingSeason = - existingRequestChildRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == season.SeasonNumber); - if (existingSeason == null) continue; - - foreach (var ep in existingSeason.Episodes) - { - // Find the episode from what we are searching - var episodeSearching = season.Episodes.FirstOrDefault(x => x.EpisodeNumber == ep.EpisodeNumber); - if (episodeSearching == null) - { - continue; - } - episodeSearching.Requested = true; - episodeSearching.Available = ep.Available; - episodeSearching.Approved = ep.Season.ChildRequest.Approved; - } - } - } - } - // TODO CHECK SONARR/RADARR - //if (sonarrCached.Select(x => x.TvdbId).Contains(tvdbid) || sickRageCache.Contains(tvdbid)) - // // compare to the sonarr/sickrage db - //{ - // item.Requested = true; - //} - } + item.CustomId = item.Id.ToString(); + await RunSearchRules(item); return item; } diff --git a/src/Ombi.Core/Models/Search/SearchMovieViewModel.cs b/src/Ombi.Core/Models/Search/SearchMovieViewModel.cs index 73732b4b5..42952cd73 100644 --- a/src/Ombi.Core/Models/Search/SearchMovieViewModel.cs +++ b/src/Ombi.Core/Models/Search/SearchMovieViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Ombi.Store.Entities; namespace Ombi.Core.Models.Search { @@ -22,5 +23,8 @@ namespace Ombi.Core.Models.Search public string Trailer { get; set; } public string Homepage { get; set; } public string ImdbId { get; set; } + public int RootPathOverride { get; set; } + public int QualityOverride { get; set; } + public override RequestType Type => RequestType.Movie; } } \ No newline at end of file diff --git a/src/Ombi.Core/Models/Search/SearchTvShowViewModel.cs b/src/Ombi.Core/Models/Search/SearchTvShowViewModel.cs index c7bbac246..90f32eda6 100644 --- a/src/Ombi.Core/Models/Search/SearchTvShowViewModel.cs +++ b/src/Ombi.Core/Models/Search/SearchTvShowViewModel.cs @@ -1,6 +1,7 @@ using Ombi.Core.Models.Requests; using Ombi.Store.Repository.Requests; using System.Collections.Generic; +using Ombi.Store.Entities; namespace Ombi.Core.Models.Search { @@ -54,5 +55,7 @@ namespace Ombi.Core.Models.Search /// This is where we have EVERY Episode for that series /// public bool FullyAvailable { get; set; } + + public override RequestType Type => RequestType.TvShow; } } \ No newline at end of file diff --git a/src/Ombi.Core/Models/Search/SearchViewModel.cs b/src/Ombi.Core/Models/Search/SearchViewModel.cs index fec2af075..2771d1be8 100644 --- a/src/Ombi.Core/Models/Search/SearchViewModel.cs +++ b/src/Ombi.Core/Models/Search/SearchViewModel.cs @@ -1,8 +1,9 @@ using System.ComponentModel.DataAnnotations.Schema; +using Ombi.Store.Entities; namespace Ombi.Core.Models.Search { - public class SearchViewModel + public abstract class SearchViewModel { public int Id { get; set; } public bool Approved { get; set; } @@ -10,6 +11,7 @@ namespace Ombi.Core.Models.Search public bool Available { get; set; } public string PlexUrl { get; set; } public string Quality { get; set; } + public abstract RequestType Type { get; } /// diff --git a/src/Ombi.Core/Rule/Interfaces/IRules.cs b/src/Ombi.Core/Rule/Interfaces/IRules.cs index a46749cd1..020991502 100644 --- a/src/Ombi.Core/Rule/Interfaces/IRules.cs +++ b/src/Ombi.Core/Rule/Interfaces/IRules.cs @@ -1,9 +1,8 @@ using System.Threading.Tasks; -using Ombi.Core.Models.Requests; namespace Ombi.Core.Rule.Interfaces { - public interface IRules where T : new() + public interface IRules { Task Execute(T obj); } diff --git a/src/Ombi.Core/Rule/RuleEvaluator.cs b/src/Ombi.Core/Rule/RuleEvaluator.cs index 2f3b96b2a..a0c272c00 100644 --- a/src/Ombi.Core/Rule/RuleEvaluator.cs +++ b/src/Ombi.Core/Rule/RuleEvaluator.cs @@ -73,7 +73,7 @@ namespace Ombi.Core.Rule } - private void GetTypes(IServiceProvider provider, Assembly ass, string baseSearchType, List> ruleList) where T : new() + private void GetTypes(IServiceProvider provider, Assembly ass, string baseSearchType, List> ruleList) { foreach (var ti in ass.DefinedTypes) { diff --git a/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs index 44670e7f8..20ad75b19 100644 --- a/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/EmbyAvailabilityRule.cs @@ -1,6 +1,9 @@ -using System.Threading.Tasks; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; +using Ombi.Store.Entities; using Ombi.Store.Repository; namespace Ombi.Core.Rule.Rules.Search @@ -20,6 +23,28 @@ namespace Ombi.Core.Rule.Rules.Search if (item != null) { obj.Available = true; + + if (obj.Type == RequestType.TvShow) + { + var searchResult = (SearchTvShowViewModel)obj; + // Let's go through the episodes now + if (searchResult.SeasonRequests.Any()) + { + var allEpisodes = EmbyContentRepository.GetAllEpisodes().Include(x => x.Series); + foreach (var season in searchResult.SeasonRequests) + { + foreach (var episode in season.Episodes) + { + var epExists = await allEpisodes.FirstOrDefaultAsync(x => + x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && item.ProviderId.ToString() == x.Series.ProviderId); + if (epExists != null) + { + episode.Available = true; + } + } + } + } + } } return Success(); } diff --git a/src/Ombi.Core/Rule/Rules/Search/ExistingRule.cs b/src/Ombi.Core/Rule/Rules/Search/ExistingRule.cs index b84f9c652..4a5faad6b 100644 --- a/src/Ombi.Core/Rule/Rules/Search/ExistingRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/ExistingRule.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; +using Ombi.Store.Entities; using Ombi.Store.Repository; using Ombi.Store.Repository.Requests; @@ -21,28 +22,75 @@ namespace Ombi.Core.Rule.Rules.Search public Task Execute(SearchViewModel obj) { - var movieRequests = Movie.GetRequest(obj.Id); - if (movieRequests != null) // Do we already have a request for this? + if (obj.Type == RequestType.Movie) { + var movieRequests = Movie.GetRequest(obj.Id); + if (movieRequests != null) // Do we already have a request for this? + { - obj.Requested = true; - obj.Approved = movieRequests.Approved; - obj.Available = movieRequests.Available; + obj.Requested = true; + obj.Approved = movieRequests.Approved; + obj.Available = movieRequests.Available; + return Task.FromResult(Success()); + } return Task.FromResult(Success()); } - - var tvRequests = Tv.GetRequest(obj.Id); - if (tvRequests != null) // Do we already have a request for this? + else { + //var tvRequests = Tv.GetRequest(obj.Id); + //if (tvRequests != null) // Do we already have a request for this? + //{ + + // obj.Requested = true; + // obj.Approved = tvRequests.ChildRequests.Any(x => x.Approved); + // obj.Available = tvRequests.ChildRequests.Any(x => x.Available); + + // return Task.FromResult(Success()); + //} + + var request = (SearchTvShowViewModel) obj; + var tvRequests = Tv.GetRequest(obj.Id); + if (tvRequests != null) // Do we already have a request for this? + { + + request.Requested = true; + request.Approved = tvRequests.ChildRequests.Any(x => x.Approved); + + // Let's modify the seasonsrequested to reflect what we have requested... + foreach (var season in request.SeasonRequests) + { + foreach (var existingRequestChildRequest in tvRequests.ChildRequests) + { + // Find the existing request season + var existingSeason = + existingRequestChildRequest.SeasonRequests.FirstOrDefault(x => x.SeasonNumber == season.SeasonNumber); + if (existingSeason == null) continue; + + foreach (var ep in existingSeason.Episodes) + { + // Find the episode from what we are searching + var episodeSearching = season.Episodes.FirstOrDefault(x => x.EpisodeNumber == ep.EpisodeNumber); + if (episodeSearching == null) + { + continue; + } + episodeSearching.Requested = true; + episodeSearching.Available = ep.Available; + episodeSearching.Approved = ep.Season.ChildRequest.Approved; + } + } + } + } + + if (request.SeasonRequests.Any() && request.SeasonRequests.All(x => x.Episodes.All(e => e.Approved))) + { + request.FullyAvailable = true; + } - obj.Requested = true; - obj.Approved = tvRequests.ChildRequests.Any(x => x.Approved); - obj.Available = tvRequests.ChildRequests.Any(x => x.Available); return Task.FromResult(Success()); } - return Task.FromResult(Success()); } } } \ No newline at end of file diff --git a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs index c293e00be..1b406cc93 100644 --- a/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/PlexAvailabilityRule.cs @@ -1,6 +1,9 @@ -using System.Threading.Tasks; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; +using Ombi.Store.Entities; using Ombi.Store.Repository; namespace Ombi.Core.Rule.Rules.Search @@ -22,6 +25,29 @@ namespace Ombi.Core.Rule.Rules.Search obj.Available = true; obj.PlexUrl = item.Url; obj.Quality = item.Quality; + + if (obj.Type == RequestType.TvShow) + { + var search = (SearchTvShowViewModel)obj; + // Let's go through the episodes now + if (search.SeasonRequests.Any()) + { + var allEpisodes = PlexContentRepository.GetAllEpisodes(); + foreach (var season in search.SeasonRequests) + { + foreach (var episode in season.Episodes) + { + var epExists = await allEpisodes.FirstOrDefaultAsync(x => + x.EpisodeNumber == episode.EpisodeNumber && x.SeasonNumber == season.SeasonNumber && + x.Series.ProviderId == item.ProviderId.ToString()); + if (epExists != null) + { + episode.Available = true; + } + } + } + } + } } return Success(); } diff --git a/src/Ombi.Core/Rule/Rules/Search/RadarrCacheRule.cs b/src/Ombi.Core/Rule/Rules/Search/RadarrCacheRule.cs index b2187e206..1c936012a 100644 --- a/src/Ombi.Core/Rule/Rules/Search/RadarrCacheRule.cs +++ b/src/Ombi.Core/Rule/Rules/Search/RadarrCacheRule.cs @@ -4,6 +4,7 @@ using Microsoft.EntityFrameworkCore; using Ombi.Core.Models.Search; using Ombi.Core.Rule.Interfaces; using Ombi.Store.Context; +using Ombi.Store.Entities; namespace Ombi.Core.Rule.Rules.Search { @@ -18,13 +19,16 @@ namespace Ombi.Core.Rule.Rules.Search public async Task Execute(SearchViewModel obj) { - // Check if it's in Radarr - var result = await _ctx.RadarrCache.FirstOrDefaultAsync(x => x.TheMovieDbId == obj.Id); - if (result != null) + if (obj.Type == RequestType.Movie) { - obj.Approved = true; // It's in radarr so it's approved... Maybe have a new property called "Processing" or something? + // Check if it's in Radarr + var result = await _ctx.RadarrCache.FirstOrDefaultAsync(x => x.TheMovieDbId == obj.Id); + if (result != null) + { + obj.Approved = + true; // It's in radarr so it's approved... Maybe have a new property called "Processing" or something? + } } - return Success(); } } diff --git a/src/Ombi.Core/Rule/Rules/Search/SonarrCacheRule.cs b/src/Ombi.Core/Rule/Rules/Search/SonarrCacheRule.cs new file mode 100644 index 000000000..d444222cf --- /dev/null +++ b/src/Ombi.Core/Rule/Rules/Search/SonarrCacheRule.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Ombi.Core.Models.Search; +using Ombi.Core.Rule.Interfaces; +using Ombi.Store.Context; +using Ombi.Store.Entities; + +namespace Ombi.Core.Rule.Rules.Search +{ + public class SonarrCacheRule : BaseSearchRule, IRules + { + public SonarrCacheRule(IOmbiContext ctx) + { + _ctx = ctx; + } + + private readonly IOmbiContext _ctx; + + public async Task Execute(SearchViewModel obj) + { + if (obj.Type == RequestType.TvShow) + { + // Check if it's in Radarr + var result = await _ctx.SonarrCache.FirstOrDefaultAsync(x => x.TvDbId == obj.Id); + if (result != null) + { + obj.Approved = + true; // It's in radarr so it's approved... Maybe have a new property called "Processing" or something? + } + } + return Success(); + } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Senders/IMovieSender.cs b/src/Ombi.Core/Senders/IMovieSender.cs index 4ed06b429..28e29cab0 100644 --- a/src/Ombi.Core/Senders/IMovieSender.cs +++ b/src/Ombi.Core/Senders/IMovieSender.cs @@ -5,6 +5,6 @@ namespace Ombi.Core { public interface IMovieSender { - Task Send(MovieRequests model, string qualityId = ""); + Task Send(MovieRequests model); } } \ No newline at end of file diff --git a/src/Ombi.Core/Senders/MovieSender.cs b/src/Ombi.Core/Senders/MovieSender.cs index 051081df2..25795b5ee 100644 --- a/src/Ombi.Core/Senders/MovieSender.cs +++ b/src/Ombi.Core/Senders/MovieSender.cs @@ -1,4 +1,5 @@ -using Ombi.Core.Settings; +using System.Linq; +using Ombi.Core.Settings; using Ombi.Settings.Settings.Models.External; using System.Threading.Tasks; using Microsoft.Extensions.Logging; @@ -21,7 +22,7 @@ namespace Ombi.Core private IRadarrApi RadarrApi { get; } private ILogger Log { get; } - public async Task Send(MovieRequests model, string qualityId = "") + public async Task Send(MovieRequests model) { //var cpSettings = await CouchPotatoSettings.GetSettingsAsync(); //var watcherSettings = await WatcherSettings.GetSettingsAsync(); @@ -39,7 +40,7 @@ namespace Ombi.Core if (radarrSettings.Enabled) { - return await SendToRadarr(model, radarrSettings, qualityId); + return await SendToRadarr(model, radarrSettings); } return new MovieSenderResult @@ -49,22 +50,16 @@ namespace Ombi.Core }; } - private async Task SendToRadarr(MovieRequests model, RadarrSettings settings, string qualityId) + private async Task SendToRadarr(MovieRequests model, RadarrSettings settings) { - var qualityProfile = 0; - if (!string.IsNullOrEmpty(qualityId)) // try to parse the passed in quality, otherwise use the settings default quality + var qualityToUse = int.Parse(settings.DefaultQualityProfile); + if (model.QualityOverride <= 0) { - int.TryParse(qualityId, out qualityProfile); + qualityToUse = model.QualityOverride; } - if (qualityProfile <= 0) - { - int.TryParse(settings.DefaultQualityProfile, out qualityProfile); - } - - //var rootFolderPath = model.RootFolderSelected <= 0 ? settings.FullRootPath : GetRootPath(model.RootFolderSelected, settings); - var rootFolderPath = settings.DefaultRootPath; // TODO Allow changing in the UI - var result = await RadarrApi.AddMovie(model.TheMovieDbId, model.Title, model.ReleaseDate.Year, qualityProfile, rootFolderPath, settings.ApiKey, settings.FullUri, !settings.AddOnly, settings.MinimumAvailability); + var rootFolderPath = model.RootPathOverride <= 0 ? settings.DefaultRootPath : await RadarrRootPath(model.RootPathOverride, settings); + var result = await RadarrApi.AddMovie(model.TheMovieDbId, model.Title, model.ReleaseDate.Year, qualityToUse, rootFolderPath, settings.ApiKey, settings.FullUri, !settings.AddOnly, settings.MinimumAvailability); if (!string.IsNullOrEmpty(result.Error?.message)) { @@ -77,5 +72,12 @@ namespace Ombi.Core } return new MovieSenderResult { Success = true, MovieSent = false }; } + + private async Task RadarrRootPath(int overrideId, RadarrSettings settings) + { + var paths = await RadarrApi.GetRootFolders(settings.ApiKey, settings.FullUri); + var selectedPath = paths.FirstOrDefault(x => x.id == overrideId); + return selectedPath.path; + } } } \ No newline at end of file diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 1be7d1dc5..1e0ba1d80 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -42,6 +42,7 @@ using Ombi.Core.Senders; using Ombi.Schedule.Jobs.Emby; using Ombi.Schedule.Jobs.Ombi; using Ombi.Schedule.Jobs.Plex; +using Ombi.Schedule.Jobs.Sonarr; using Ombi.Schedule.Ombi; using Ombi.Store.Repository.Requests; using PlexContentCacher = Ombi.Schedule.Jobs.Plex.PlexContentCacher; @@ -142,6 +143,7 @@ namespace Ombi.DependencyInjection services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/Ombi.Helpers/CacheKeys.cs b/src/Ombi.Helpers/CacheKeys.cs index f1c64fa38..db66d4e13 100644 --- a/src/Ombi.Helpers/CacheKeys.cs +++ b/src/Ombi.Helpers/CacheKeys.cs @@ -16,5 +16,7 @@ namespace Ombi.Helpers public const string TopRatedMovies = nameof(TopRatedMovies); public const string UpcomingMovies = nameof(UpcomingMovies); public const string NowPlayingMovies = nameof(NowPlayingMovies); + public const string RadarrRootProfiles = nameof(RadarrRootProfiles); + public const string RadarrQualityProfiles = nameof(RadarrQualityProfiles); } } diff --git a/src/Ombi.Helpers/LoggingEvents.cs b/src/Ombi.Helpers/LoggingEvents.cs index e4a349049..5d6b17aa5 100644 --- a/src/Ombi.Helpers/LoggingEvents.cs +++ b/src/Ombi.Helpers/LoggingEvents.cs @@ -11,10 +11,11 @@ namespace Ombi.Helpers public static EventId Cacher => new EventId(2000); public static EventId RadarrCacher => new EventId(2001); - public static EventId PlexEpisodeCacher => new EventId(2001); - public static EventId EmbyContentCacher => new EventId(2002); - public static EventId PlexUserImporter => new EventId(2003); - public static EventId EmbyUserImporter => new EventId(2004); + public static EventId PlexEpisodeCacher => new EventId(2002); + public static EventId EmbyContentCacher => new EventId(2003); + public static EventId PlexUserImporter => new EventId(2004); + public static EventId EmbyUserImporter => new EventId(2005); + public static EventId SonarrCacher => new EventId(2006); public static EventId MovieSender => new EventId(3000); diff --git a/src/Ombi.Schedule/JobSetup.cs b/src/Ombi.Schedule/JobSetup.cs index 6b13a10bb..c0fb6d5f8 100644 --- a/src/Ombi.Schedule/JobSetup.cs +++ b/src/Ombi.Schedule/JobSetup.cs @@ -3,6 +3,7 @@ using Ombi.Schedule.Jobs; using Ombi.Schedule.Jobs.Emby; using Ombi.Schedule.Jobs.Plex; using Ombi.Schedule.Jobs.Radarr; +using Ombi.Schedule.Jobs.Sonarr; using Ombi.Schedule.Ombi; namespace Ombi.Schedule @@ -11,7 +12,7 @@ namespace Ombi.Schedule { public JobSetup(IPlexContentCacher plexContentCacher, IRadarrCacher radarrCacher, IOmbiAutomaticUpdater updater, IEmbyContentCacher embyCacher, IPlexUserImporter userImporter, - IEmbyUserImporter embyUserImporter) + IEmbyUserImporter embyUserImporter, ISonarrCacher cache) { PlexContentCacher = plexContentCacher; RadarrCacher = radarrCacher; @@ -19,6 +20,7 @@ namespace Ombi.Schedule EmbyContentCacher = embyCacher; PlexUserImporter = userImporter; EmbyUserImporter = embyUserImporter; + SonarrCacher = cache; } private IPlexContentCacher PlexContentCacher { get; } @@ -27,17 +29,17 @@ namespace Ombi.Schedule private IPlexUserImporter PlexUserImporter { get; } private IEmbyContentCacher EmbyContentCacher { get; } private IEmbyUserImporter EmbyUserImporter { get; } + private ISonarrCacher SonarrCacher { get; } public void Setup() { RecurringJob.AddOrUpdate(() => PlexContentCacher.CacheContent(), Cron.Hourly(20)); RecurringJob.AddOrUpdate(() => EmbyContentCacher.Start(), Cron.Hourly(5)); RecurringJob.AddOrUpdate(() => RadarrCacher.CacheContent(), Cron.Hourly(10)); - RecurringJob.AddOrUpdate(() => PlexUserImporter.Start(), Cron.Daily(1)); + RecurringJob.AddOrUpdate(() => RadarrCacher.CacheContent(), Cron.Hourly(15)); + RecurringJob.AddOrUpdate(() => PlexUserImporter.Start(), Cron.Daily(5)); RecurringJob.AddOrUpdate(() => EmbyUserImporter.Start(), Cron.Daily); - RecurringJob.AddOrUpdate(() => Updater.Update(null), Cron.Daily(3)); - - //BackgroundJob.Enqueue(() => PlexUserImporter.Start()); + RecurringJob.AddOrUpdate(() => Updater.Update(null), Cron.HourInterval(6)); } } } diff --git a/src/Ombi.Schedule/Jobs/Radarr/RadarrCacher.cs b/src/Ombi.Schedule/Jobs/Radarr/RadarrCacher.cs index fb42be325..9667af648 100644 --- a/src/Ombi.Schedule/Jobs/Radarr/RadarrCacher.cs +++ b/src/Ombi.Schedule/Jobs/Radarr/RadarrCacher.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -28,8 +29,11 @@ namespace Ombi.Schedule.Jobs.Radarr private ILogger Logger { get; } private readonly IOmbiContext _ctx; + private static readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1); + public async Task CacheContent() { + await SemaphoreSlim.WaitAsync(); try { var settings = RadarrSettings.GetSettings(); @@ -48,7 +52,7 @@ namespace Ombi.Schedule.Jobs.Radarr { if (m.tmdbId > 0) { - movieIds.Add(new RadarrCache { TheMovieDbId = m.tmdbId }); + movieIds.Add(new RadarrCache {TheMovieDbId = m.tmdbId}); } else { @@ -70,6 +74,10 @@ namespace Ombi.Schedule.Jobs.Radarr { Logger.LogInformation(LoggingEvents.RadarrCacher, "Radarr is not setup, cannot cache episodes"); } + finally + { + SemaphoreSlim.Release(); + } } public async Task> GetCachedContent() diff --git a/src/Ombi.Schedule/Jobs/Sonarr/ISonarrCacher.cs b/src/Ombi.Schedule/Jobs/Sonarr/ISonarrCacher.cs new file mode 100644 index 000000000..e3b968784 --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Sonarr/ISonarrCacher.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Ombi.Schedule.Jobs.Sonarr +{ + public interface ISonarrCacher + { + Task Start(); + } +} \ No newline at end of file diff --git a/src/Ombi.Schedule/Jobs/Sonarr/SonarrCacher.cs b/src/Ombi.Schedule/Jobs/Sonarr/SonarrCacher.cs new file mode 100644 index 000000000..591f02747 --- /dev/null +++ b/src/Ombi.Schedule/Jobs/Sonarr/SonarrCacher.cs @@ -0,0 +1,116 @@ +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Ombi.Api.Sonarr; +using Ombi.Core.Settings; +using Ombi.Core.Settings.Models.External; +using Ombi.Helpers; +using Ombi.Store.Context; +using Ombi.Store.Entities; + +namespace Ombi.Schedule.Jobs.Sonarr +{ + public class SonarrCacher : ISonarrCacher + { + public SonarrCacher(ISettingsService s, ISonarrApi api, ILogger l, IOmbiContext ctx) + { + _settings = s; + _api = api; + _log = l; + } + + private readonly ISettingsService _settings; + private readonly ISonarrApi _api; + private readonly ILogger _log; + private readonly IOmbiContext _ctx; + + private static readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1); + public async Task Start() + { + await SemaphoreSlim.WaitAsync(); + try + { + var settings = await _settings.GetSettingsAsync(); + if (!settings.Enabled) + { + return; + } + var series = await _api.GetSeries(settings.ApiKey, settings.FullUri); + if (series != null) + { + var ids = series.Select(x => x.tvdbId); + + await _ctx.Database.ExecuteSqlCommandAsync("DELETE FROM SonarrCache"); + var entites = ids.Select(id => new SonarrCache {TvDbId = id}).ToList(); + + await _ctx.SonarrCache.AddRangeAsync(entites); + await _ctx.SaveChangesAsync(); + } + } + catch (Exception e) + { + _log.LogError(LoggingEvents.SonarrCacher, e, "Exception when trying to cache Sonarr"); + } + finally + { + SemaphoreSlim.Release(); + } + } + + + //public void Queued() + //{ + // var settings = SonarrSettings.GetSettings(); + // if (settings.Enabled) + // { + // Job.SetRunning(true, JobNames.SonarrCacher); + // try + // { + // var series = SonarrApi.GetSeries(settings.ApiKey, settings.FullUri); + // if (series != null) + // { + // Cache.Set(CacheKeys.SonarrQueued, series, CacheKeys.TimeFrameMinutes.SchedulerCaching); + // } + // } + // catch (System.Exception ex) + // { + // Log.Error(ex, "Failed caching queued items from Sonarr"); + // } + // finally + // { + // Job.Record(JobNames.SonarrCacher); + // Job.SetRunning(false, JobNames.SonarrCacher); + // } + // } + //} + + //// we do not want to set here... + //public IEnumerable QueuedIds() + //{ + // var result = new List(); + + // var series = Cache.Get>(CacheKeys.SonarrQueued); + // if (series != null) + // { + // foreach (var s in series) + // { + // var cached = new SonarrCachedResult { TvdbId = s.tvdbId }; + // foreach (var season in s.seasons) + // { + // cached.Seasons.Add(new SonarrSeasons + // { + // SeasonNumber = season.seasonNumber, + // Monitored = season.monitored + // }); + // } + + // result.Add(cached); + // } + // } + // return result; + //} + } +} \ No newline at end of file diff --git a/src/Ombi.Schedule/Ombi.Schedule.csproj b/src/Ombi.Schedule/Ombi.Schedule.csproj index 328194252..04106e767 100644 --- a/src/Ombi.Schedule/Ombi.Schedule.csproj +++ b/src/Ombi.Schedule/Ombi.Schedule.csproj @@ -23,6 +23,7 @@ + diff --git a/src/Ombi.Store/Context/IOmbiContext.cs b/src/Ombi.Store/Context/IOmbiContext.cs index f4a7910e1..63612ea8c 100644 --- a/src/Ombi.Store/Context/IOmbiContext.cs +++ b/src/Ombi.Store/Context/IOmbiContext.cs @@ -33,6 +33,7 @@ namespace Ombi.Store.Context DbSet MovieIssues { get; set; } DbSet TvIssues { get; set; } DbSet Tokens { get; set; } + DbSet SonarrCache { get; set; } EntityEntry Update(object entity); EntityEntry Update(TEntity entity) where TEntity : class; } diff --git a/src/Ombi.Store/Context/OmbiContext.cs b/src/Ombi.Store/Context/OmbiContext.cs index 257e6a3c8..ebbab4b21 100644 --- a/src/Ombi.Store/Context/OmbiContext.cs +++ b/src/Ombi.Store/Context/OmbiContext.cs @@ -38,6 +38,7 @@ namespace Ombi.Store.Context public DbSet Audit { get; set; } public DbSet Tokens { get; set; } + public DbSet SonarrCache { get; set; } public DbSet ApplicationConfigurations { get; set; } diff --git a/src/Ombi.Store/Entities/Requests/MovieRequests.cs b/src/Ombi.Store/Entities/Requests/MovieRequests.cs index 11b12c7f6..680a1c8bb 100644 --- a/src/Ombi.Store/Entities/Requests/MovieRequests.cs +++ b/src/Ombi.Store/Entities/Requests/MovieRequests.cs @@ -11,5 +11,8 @@ namespace Ombi.Store.Entities.Requests public int? IssueId { get; set; } [ForeignKey(nameof(IssueId))] public List Issues { get; set; } + + public int RootPathOverride { get; set; } + public int QualityOverride { get; set; } } } diff --git a/src/Ombi.Store/Entities/SonarrCache.cs b/src/Ombi.Store/Entities/SonarrCache.cs new file mode 100644 index 000000000..33e06f7d9 --- /dev/null +++ b/src/Ombi.Store/Entities/SonarrCache.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Ombi.Store.Entities +{ + [Table("SonarrCache")] + public class SonarrCache : Entity + { + public int TvDbId { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Migrations/20171002113357_SonarrCacher.Designer.cs b/src/Ombi.Store/Migrations/20171002113357_SonarrCacher.Designer.cs new file mode 100644 index 000000000..9ea6c0745 --- /dev/null +++ b/src/Ombi.Store/Migrations/20171002113357_SonarrCacher.Designer.cs @@ -0,0 +1,747 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using Ombi.Helpers; +using Ombi.Store.Context; +using Ombi.Store.Entities; +using System; + +namespace Ombi.Store.Migrations +{ + [DbContext(typeof(OmbiContext))] + [Migration("20171002113357_SonarrCacher")] + partial class SonarrCacher + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.0-rtm-26452"); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Name") + .HasMaxLength(256); + + b.Property("NormalizedName") + .HasMaxLength(256); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasName("RoleNameIndex"); + + b.ToTable("AspNetRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("RoleId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ClaimType"); + + b.Property("ClaimValue"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider"); + + b.Property("ProviderKey"); + + b.Property("ProviderDisplayName"); + + b.Property("UserId") + .IsRequired(); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId"); + + b.Property("RoleId"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId"); + + b.Property("LoginProvider"); + + b.Property("Name"); + + b.Property("Value"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.ApplicationConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Type"); + + b.Property("Value"); + + b.HasKey("Id"); + + b.ToTable("ApplicationConfiguration"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Audit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuditArea"); + + b.Property("AuditType"); + + b.Property("DateTime"); + + b.Property("Description"); + + b.Property("User"); + + b.HasKey("Id"); + + b.ToTable("Audit"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("EmbyId") + .IsRequired(); + + b.Property("ProviderId"); + + b.Property("Title"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.ToTable("EmbyContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("EmbyId"); + + b.Property("EpisodeNumber"); + + b.Property("ParentId"); + + b.Property("ProviderId"); + + b.Property("SeasonNumber"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("EmbyEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.GlobalSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Content"); + + b.Property("SettingsName"); + + b.HasKey("Id"); + + b.ToTable("GlobalSettings"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.NotificationTemplates", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Agent"); + + b.Property("Enabled"); + + b.Property("Message"); + + b.Property("NotificationType"); + + b.Property("Subject"); + + b.HasKey("Id"); + + b.ToTable("NotificationTemplates"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.OmbiUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AccessFailedCount"); + + b.Property("Alias"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken(); + + b.Property("Email") + .HasMaxLength(256); + + b.Property("EmailConfirmed"); + + b.Property("LastLoggedIn"); + + b.Property("LockoutEnabled"); + + b.Property("LockoutEnd"); + + b.Property("NormalizedEmail") + .HasMaxLength(256); + + b.Property("NormalizedUserName") + .HasMaxLength(256); + + b.Property("PasswordHash"); + + b.Property("PhoneNumber"); + + b.Property("PhoneNumberConfirmed"); + + b.Property("ProviderUserId"); + + b.Property("SecurityStamp"); + + b.Property("TwoFactorEnabled"); + + b.Property("UserName") + .HasMaxLength(256); + + b.Property("UserType"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasName("UserNameIndex"); + + b.ToTable("AspNetUsers"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AddedAt"); + + b.Property("Key"); + + b.Property("ProviderId"); + + b.Property("Quality"); + + b.Property("ReleaseYear"); + + b.Property("Title"); + + b.Property("Type"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.ToTable("PlexContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("EpisodeNumber"); + + b.Property("GrandparentKey"); + + b.Property("Key"); + + b.Property("ParentKey"); + + b.Property("SeasonNumber"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("GrandparentKey"); + + b.ToTable("PlexEpisode"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ParentKey"); + + b.Property("PlexContentId"); + + b.Property("SeasonKey"); + + b.Property("SeasonNumber"); + + b.HasKey("Id"); + + b.HasIndex("PlexContentId"); + + b.ToTable("PlexSeasonsContent"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.RadarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TheMovieDbId"); + + b.HasKey("Id"); + + b.ToTable("RadarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("IssueId"); + + b.Property("ParentRequestId"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("ParentRequestId"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("ChildRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieIssues", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("IssueId"); + + b.Property("MovieId"); + + b.Property("Subect"); + + b.HasKey("Id"); + + b.HasIndex("IssueId"); + + b.HasIndex("MovieId"); + + b.ToTable("MovieIssues"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("Denied"); + + b.Property("DeniedReason"); + + b.Property("ImdbId"); + + b.Property("IssueId"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("QualityOverride"); + + b.Property("ReleaseDate"); + + b.Property("RequestType"); + + b.Property("RequestedDate"); + + b.Property("RequestedUserId"); + + b.Property("RootPathOverride"); + + b.Property("Status"); + + b.Property("TheMovieDbId"); + + b.Property("Title"); + + b.HasKey("Id"); + + b.HasIndex("RequestedUserId"); + + b.ToTable("MovieRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvIssues", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Description"); + + b.Property("IssueId"); + + b.Property("Subect"); + + b.Property("TvId"); + + b.HasKey("Id"); + + b.HasIndex("IssueId"); + + b.HasIndex("TvId"); + + b.ToTable("TvIssues"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ImdbId"); + + b.Property("Overview"); + + b.Property("PosterPath"); + + b.Property("ReleaseDate"); + + b.Property("RootFolder"); + + b.Property("Status"); + + b.Property("Title"); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("TvRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SonarrCache"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Token"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AirDate"); + + b.Property("Approved"); + + b.Property("Available"); + + b.Property("EpisodeNumber"); + + b.Property("Requested"); + + b.Property("SeasonId"); + + b.Property("Title"); + + b.Property("Url"); + + b.HasKey("Id"); + + b.HasIndex("SeasonId"); + + b.ToTable("EpisodeRequests"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChildRequestId"); + + b.Property("SeasonNumber"); + + b.HasKey("Id"); + + b.HasIndex("ChildRequestId"); + + b.ToTable("SeasonRequests"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole") + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.EmbyEpisode", b => + { + b.HasOne("Ombi.Store.Entities.EmbyContent", "Series") + .WithMany("Episodes") + .HasForeignKey("ParentId") + .HasPrincipalKey("EmbyId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexEpisode", b => + { + b.HasOne("Ombi.Store.Entities.PlexContent", "Series") + .WithMany("Episodes") + .HasForeignKey("GrandparentKey") + .HasPrincipalKey("Key") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.PlexSeasonsContent", b => + { + b.HasOne("Ombi.Store.Entities.PlexContent") + .WithMany("Seasons") + .HasForeignKey("PlexContentId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b => + { + b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest") + .WithMany("ChildRequests") + .HasForeignKey("ParentRequestId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieIssues", b => + { + b.HasOne("Ombi.Store.Entities.Requests.MovieRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.Requests.MovieRequests", "Movie") + .WithMany() + .HasForeignKey("MovieId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.MovieRequests", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser") + .WithMany() + .HasForeignKey("RequestedUserId"); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Requests.TvIssues", b => + { + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests") + .WithMany("Issues") + .HasForeignKey("IssueId"); + + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "Child") + .WithMany() + .HasForeignKey("TvId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => + { + b.HasOne("Ombi.Store.Entities.OmbiUser", "User") + .WithMany() + .HasForeignKey("UserId"); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.EpisodeRequests", b => + { + b.HasOne("Ombi.Store.Repository.Requests.SeasonRequests", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("Ombi.Store.Repository.Requests.SeasonRequests", b => + { + b.HasOne("Ombi.Store.Entities.Requests.ChildRequests", "ChildRequest") + .WithMany("SeasonRequests") + .HasForeignKey("ChildRequestId") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/Ombi.Store/Migrations/20171002113357_SonarrCacher.cs b/src/Ombi.Store/Migrations/20171002113357_SonarrCacher.cs new file mode 100644 index 000000000..36bdbca20 --- /dev/null +++ b/src/Ombi.Store/Migrations/20171002113357_SonarrCacher.cs @@ -0,0 +1,53 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace Ombi.Store.Migrations +{ + public partial class SonarrCacher : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "QualityOverride", + table: "MovieRequests", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "RootPathOverride", + table: "MovieRequests", + type: "INTEGER", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateTable( + name: "SonarrCache", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + TvDbId = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SonarrCache", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SonarrCache"); + + migrationBuilder.DropColumn( + name: "QualityOverride", + table: "MovieRequests"); + + migrationBuilder.DropColumn( + name: "RootPathOverride", + table: "MovieRequests"); + } + } +} diff --git a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs index 1a46eb954..e744a7fd6 100644 --- a/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs +++ b/src/Ombi.Store/Migrations/OmbiContextModelSnapshot.cs @@ -460,6 +460,8 @@ namespace Ombi.Store.Migrations b.Property("PosterPath"); + b.Property("QualityOverride"); + b.Property("ReleaseDate"); b.Property("RequestType"); @@ -468,6 +470,8 @@ namespace Ombi.Store.Migrations b.Property("RequestedUserId"); + b.Property("RootPathOverride"); + b.Property("Status"); b.Property("TheMovieDbId"); @@ -529,6 +533,18 @@ namespace Ombi.Store.Migrations b.ToTable("TvRequests"); }); + modelBuilder.Entity("Ombi.Store.Entities.SonarrCache", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("TvDbId"); + + b.HasKey("Id"); + + b.ToTable("SonarrCache"); + }); + modelBuilder.Entity("Ombi.Store.Entities.Tokens", b => { b.Property("Id") diff --git a/src/Ombi.TheMovieDbApi/Models/MovieResponse.cs b/src/Ombi.TheMovieDbApi/Models/MovieResponse.cs index f619f647a..17aceca5d 100644 --- a/src/Ombi.TheMovieDbApi/Models/MovieResponse.cs +++ b/src/Ombi.TheMovieDbApi/Models/MovieResponse.cs @@ -45,8 +45,8 @@ namespace Ombi.TheMovieDbApi.Models public ProductionCompanies[] production_companies { get; set; } public ProductionCountries[] production_countries { get; set; } public string release_date { get; set; } - public int revenue { get; set; } - public int runtime { get; set; } + public float revenue { get; set; } + public float runtime { get; set; } public SpokenLanguages[] spoken_languages { get; set; } public string status { get; set; } public string tagline { get; set; } diff --git a/src/Ombi.TheMovieDbApi/Models/MovieResponseDTO.cs b/src/Ombi.TheMovieDbApi/Models/MovieResponseDTO.cs index b679ba5cf..0fd27a23f 100644 --- a/src/Ombi.TheMovieDbApi/Models/MovieResponseDTO.cs +++ b/src/Ombi.TheMovieDbApi/Models/MovieResponseDTO.cs @@ -15,8 +15,8 @@ public float Popularity { get; set; } public string PosterPath { get; set; } public string ReleaseDate { get; set; } - public int Revenue { get; set; } - public int Runtime { get; set; } + public float Revenue { get; set; } + public float Runtime { get; set; } public string Status { get; set; } public string Tagline { get; set; } public string Title { get; set; } diff --git a/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts b/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts index 70aeed4b9..e67c63ed0 100644 --- a/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts +++ b/src/Ombi/ClientApp/app/interfaces/IRequestModel.ts @@ -79,6 +79,8 @@ export interface IRequestGrid { export interface IMovieRequests extends IFullBaseRequest { theMovieDbId: number; + rootPathOverride: number; + qualityOverride: number; } export interface IFullBaseRequest extends IBaseRequest { diff --git a/src/Ombi/ClientApp/app/landingpage/landingpage.component.html b/src/Ombi/ClientApp/app/landingpage/landingpage.component.html index 2678f4bb9..4372394c3 100644 --- a/src/Ombi/ClientApp/app/landingpage/landingpage.component.html +++ b/src/Ombi/ClientApp/app/landingpage/landingpage.component.html @@ -41,7 +41,7 @@
- +
diff --git a/src/Ombi/ClientApp/app/login/resetpassword.component.html b/src/Ombi/ClientApp/app/login/resetpassword.component.html index cd109ddff..c990da5dc 100644 --- a/src/Ombi/ClientApp/app/login/resetpassword.component.html +++ b/src/Ombi/ClientApp/app/login/resetpassword.component.html @@ -7,7 +7,7 @@ include the remember me checkbox
-
+