feat(radarr): 4K Requests and Radarr 4K support

* feat: updated radarr settings API to support 4k

* feat: refactored the radarr setting page to support the new model

* feat: Added 4k radarr to the settings page

* feat: Added the new Movie 4k Request

* feat: Got some of the backend rules done

* feat: Made a load of progress

* Removed the csproj ref

* feat: fixed the radarr ui

* feat: fixed up all the movie requests page

* feat: Hide the 4K buttons when the user does not have the 4k permission

* fix: fixed the templateref issue

* test: fixed up all the tests

* feat: Added migrations for media sever quality. Emby and Radarr Sync jobs now pull the quality

* feat: Done the media sync jobs

* feat: plex availability checker

* feat: Updated the jellyfin availability checker to check for 4k

* feat: updated emby availbility checker to check for 4k

* feat: almost got it all working now

* feat: Added 4k approve to the request list options

* feat: Added 4k to the requests list and bulk approve

* feat: Added the features service

* feat: added feature update to the frontend

* feat: got the features page working

* feat: Applied the feature service on the backend

* feat: added the feature flag on the UI

* feat: added 4k to the card
This commit is contained in:
Jamie 2022-02-14 22:08:09 +00:00 committed by GitHub
commit ba88848866
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
153 changed files with 12438 additions and 784 deletions

View file

@ -18,9 +18,9 @@ namespace Ombi.Core.Engine.Interfaces
Task RemoveAllMovieRequests();
Task<MovieRequests> GetRequest(int requestId);
Task<MovieRequests> UpdateMovieRequest(MovieRequests request);
Task<RequestEngineResult> ApproveMovie(MovieRequests request);
Task<RequestEngineResult> ApproveMovieById(int requestId);
Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason);
Task<RequestEngineResult> ApproveMovie(MovieRequests request, bool is4K);
Task<RequestEngineResult> ApproveMovieById(int requestId, bool is4K);
Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason, bool is4K);
Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder);
Task<RequestsViewModel<MovieRequests>> GetUnavailableRequests(int count, int position, string sortProperty,

View file

@ -19,11 +19,11 @@ namespace Ombi.Core.Engine.Interfaces
Task<IEnumerable<T>> GetRequests();
Task<bool> UserHasRequest(string userId);
Task<RequestEngineResult> MarkUnavailable(int modelId);
Task<RequestEngineResult> MarkAvailable(int modelId);
Task<RequestEngineResult> MarkUnavailable(int modelId, bool is4K);
Task<RequestEngineResult> MarkAvailable(int modelId, bool is4K);
Task<int> GetTotal();
Task UnSubscribeRequest(int requestId, RequestType type);
Task SubscribeToRequest(int requestId, RequestType type);
Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken);
Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken);
}
}

View file

@ -22,6 +22,7 @@ using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository;
using Ombi.Core.Models;
using System.Threading;
using Ombi.Core.Services;
namespace Ombi.Core.Engine
{
@ -30,7 +31,8 @@ namespace Ombi.Core.Engine
public MovieRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService)
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, IMediaCacheService mediaCacheService,
IFeatureService featureService)
: base(user, requestService, r, manager, cache, ombiSettings, sub)
{
MovieApi = movieApi;
@ -39,6 +41,7 @@ namespace Ombi.Core.Engine
Logger = log;
_requestLog = rl;
_mediaCacheService = mediaCacheService;
_featureService = featureService;
}
private IMovieDbApi MovieApi { get; }
@ -47,6 +50,7 @@ namespace Ombi.Core.Engine
private ILogger<MovieRequestEngine> Logger { get; }
private readonly IRepository<RequestLog> _requestLog;
private readonly IMediaCacheService _mediaCacheService;
private readonly IFeatureService _featureService;
/// <summary>
/// Requests the movie.
@ -72,7 +76,8 @@ namespace Ombi.Core.Engine
var userDetails = await GetUser();
var canRequestOnBehalf = model.RequestOnBehalf.HasValue();
var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser) || await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin);
var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser)
|| await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin);
if (canRequestOnBehalf && !isAdmin)
{
return new RequestEngineResult
@ -93,27 +98,53 @@ namespace Ombi.Core.Engine
};
}
var requestModel = new MovieRequests
var is4kFeatureEnabled = await _featureService.FeatureEnabled(FeatureNames.Movie4KRequests);
var is4kRequest = is4kFeatureEnabled && model.Is4kRequest;
MovieRequests requestModel;
bool isExisting = false;
// Do we already have a request? 4k or non 4k
var existingRequest = await MovieRepository.GetRequestAsync(movieInfo.Id);
if (existingRequest != null && is4kFeatureEnabled)
{
TheMovieDbId = movieInfo.Id,
RequestType = RequestType.Movie,
Overview = movieInfo.Overview,
ImdbId = movieInfo.ImdbId,
PosterPath = PosterPathHelper.FixPosterPath(movieInfo.PosterPath),
Title = movieInfo.Title,
ReleaseDate = !string.IsNullOrEmpty(movieInfo.ReleaseDate)
? DateTime.Parse(movieInfo.ReleaseDate)
: DateTime.MinValue,
Status = movieInfo.Status,
RequestedDate = DateTime.UtcNow,
Approved = false,
RequestedUserId = canRequestOnBehalf ? model.RequestOnBehalf : userDetails.Id,
Background = movieInfo.BackdropPath,
LangCode = model.LanguageCode,
RequestedByAlias = model.RequestedByAlias,
RootPathOverride = model.RootFolderOverride.GetValueOrDefault(),
QualityOverride = model.QualityPathOverride.GetValueOrDefault()
};
if (model.Is4kRequest)
{
existingRequest.Is4kRequest = true;
existingRequest.RequestedDate4k = DateTime.Now;
}
else
{
existingRequest.RequestedDate = DateTime.Now;
}
isExisting = true;
requestModel = existingRequest;
}
else
{
requestModel = new MovieRequests
{
TheMovieDbId = movieInfo.Id,
RequestType = RequestType.Movie,
Overview = movieInfo.Overview,
ImdbId = movieInfo.ImdbId,
PosterPath = PosterPathHelper.FixPosterPath(movieInfo.PosterPath),
Title = movieInfo.Title,
ReleaseDate = !string.IsNullOrEmpty(movieInfo.ReleaseDate)
? DateTime.Parse(movieInfo.ReleaseDate)
: DateTime.MinValue,
Status = movieInfo.Status,
RequestedDate = model.Is4kRequest ? DateTime.MinValue : DateTime.Now,
Approved = false,
RequestedUserId = canRequestOnBehalf ? model.RequestOnBehalf : userDetails.Id,
Background = movieInfo.BackdropPath,
LangCode = model.LanguageCode,
RequestedByAlias = model.RequestedByAlias,
RootPathOverride = model.RootFolderOverride.GetValueOrDefault(),
QualityOverride = model.QualityPathOverride.GetValueOrDefault(),
RequestedDate4k = model.Is4kRequest ? DateTime.Now : DateTime.MinValue,
Is4kRequest = model.Is4kRequest
};
}
var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US");
requestModel.DigitalReleaseDate = usDates?.ReleaseDate
@ -132,10 +163,10 @@ namespace Ombi.Core.Engine
if (requestModel.Approved) // The rules have auto approved this
{
var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf);
var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf, isExisting, is4kRequest);
if (requestEngineResult.Result)
{
var result = await ApproveMovie(requestModel);
var result = await ApproveMovie(requestModel, model.Is4kRequest);
if (result.IsError)
{
Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message);
@ -153,7 +184,7 @@ namespace Ombi.Core.Engine
// If there are no providers then it's successful but movie has not been sent
}
return await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf);
return await AddMovieRequest(requestModel, fullMovieName, model.RequestOnBehalf, isExisting, is4kRequest);
}
@ -508,13 +539,13 @@ namespace Ombi.Core.Engine
return results;
}
public async Task<RequestEngineResult> ApproveMovieById(int requestId)
public async Task<RequestEngineResult> ApproveMovieById(int requestId, bool is4K)
{
var request = await MovieRepository.Find(requestId);
return await ApproveMovie(request);
return await ApproveMovie(request, is4K);
}
public async Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason)
public async Task<RequestEngineResult> DenyMovieById(int modelId, string denyReason, bool is4K)
{
var request = await MovieRepository.Find(modelId);
if (request == null)
@ -525,8 +556,16 @@ namespace Ombi.Core.Engine
};
}
request.Denied = true;
request.DeniedReason = denyReason;
if (is4K)
{
request.Denied4K = true;
request.DeniedReason4K = denyReason;
}
else
{
request.Denied = true;
request.DeniedReason = denyReason;
}
await MovieRepository.Update(request);
await _mediaCacheService.Purge();
@ -540,7 +579,7 @@ namespace Ombi.Core.Engine
};
}
public async Task<RequestEngineResult> ApproveMovie(MovieRequests request)
public async Task<RequestEngineResult> ApproveMovie(MovieRequests request, bool is4K)
{
if (request == null)
{
@ -550,9 +589,18 @@ namespace Ombi.Core.Engine
};
}
request.MarkedAsApproved = DateTime.Now;
request.Approved = true;
request.Denied = false;
if (is4K)
{
request.MarkedAsApproved4K = DateTime.Now;
request.Approved4K = true;
request.Denied4K = false;
}
else
{
request.MarkedAsApproved = DateTime.Now;
request.Approved = true;
request.Denied = false;
}
await MovieRepository.Update(request);
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty);
@ -562,7 +610,7 @@ namespace Ombi.Core.Engine
}
await _mediaCacheService.Purge();
return await ProcessSendingMovie(request);
return await ProcessSendingMovie(request, is4K);
}
public async Task<RequestEngineResult> RequestCollection(int collectionId, CancellationToken cancellationToken)
@ -590,11 +638,11 @@ namespace Ombi.Core.Engine
return new RequestEngineResult { Result = true, Message = $"The collection {collections.name} has been successfully added!", RequestId = results.FirstOrDefault().RequestId };
}
private async Task<RequestEngineResult> ProcessSendingMovie(MovieRequests request)
private async Task<RequestEngineResult> ProcessSendingMovie(MovieRequests request, bool is4K)
{
if (request.Approved)
{
var result = await Sender.Send(request);
var result = await Sender.Send(request, is4K);
if (result.Success && result.Sent)
{
return new RequestEngineResult
@ -662,7 +710,7 @@ namespace Ombi.Core.Engine
var result = await CheckCanManageRequest(request);
if (result.IsError)
return result;
await MovieRepository.Delete(request);
await _mediaCacheService.Purge();
return new RequestEngineResult
@ -683,7 +731,7 @@ namespace Ombi.Core.Engine
return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
}
public async Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken)
public async Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken)
{
var request = await MovieRepository.Find(requestId);
if (request == null)
@ -695,10 +743,10 @@ namespace Ombi.Core.Engine
};
}
return await ProcessSendingMovie(request);
return await ProcessSendingMovie(request, is4K);
}
public async Task<RequestEngineResult> MarkUnavailable(int modelId)
public async Task<RequestEngineResult> MarkUnavailable(int modelId, bool is4K)
{
var request = await MovieRepository.Find(modelId);
if (request == null)
@ -709,7 +757,14 @@ namespace Ombi.Core.Engine
};
}
request.Available = false;
if (is4K)
{
request.Available4K = false;
}
else
{
request.Available = false;
}
await MovieRepository.Update(request);
await _mediaCacheService.Purge();
@ -720,7 +775,7 @@ namespace Ombi.Core.Engine
};
}
public async Task<RequestEngineResult> MarkAvailable(int modelId)
public async Task<RequestEngineResult> MarkAvailable(int modelId, bool is4K)
{
var request = await MovieRepository.Find(modelId);
if (request == null)
@ -730,9 +785,16 @@ namespace Ombi.Core.Engine
ErrorMessage = "Request does not exist"
};
}
request.Available = true;
request.MarkedAsAvailable = DateTime.Now;
if (!is4K)
{
request.Available = true;
request.MarkedAsAvailable = DateTime.Now;
}
else
{
request.Available4K = true;
request.MarkedAsAvailable4K = DateTime.Now;
}
await NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await MovieRepository.Update(request);
await _mediaCacheService.Purge();
@ -744,9 +806,20 @@ namespace Ombi.Core.Engine
};
}
private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string movieName, string requestOnBehalf)
private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string movieName, string requestOnBehalf, bool isExisting, bool is4k)
{
await MovieRepository.Add(model);
if (is4k)
{
model.Has4KRequest = true;
}
if (!isExisting)
{
await MovieRepository.Add(model);
}
else
{
await MovieRepository.Update(model);
}
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, requestOnBehalf);
if (result.Success)

View file

@ -793,7 +793,7 @@ namespace Ombi.Core.Engine
return await TvRepository.GetChild().AnyAsync(x => x.RequestedUserId == userId);
}
public async Task<RequestEngineResult> MarkUnavailable(int modelId)
public async Task<RequestEngineResult> MarkUnavailable(int modelId, bool is4K)
{
var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == modelId);
if (request == null)
@ -821,7 +821,7 @@ namespace Ombi.Core.Engine
};
}
public async Task<RequestEngineResult> MarkAvailable(int modelId)
public async Task<RequestEngineResult> MarkAvailable(int modelId, bool is4K)
{
ChildRequests request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == modelId);
if (request == null)
@ -918,7 +918,7 @@ namespace Ombi.Core.Engine
return await AfterRequest(model.ChildRequests.FirstOrDefault(), requestOnBehalf);
}
public async Task<RequestEngineResult> ReProcessRequest(int requestId, CancellationToken cancellationToken)
public async Task<RequestEngineResult> ReProcessRequest(int requestId, bool is4K, CancellationToken cancellationToken)
{
var request = await TvRepository.GetChild().FirstOrDefaultAsync(x => x.Id == requestId, cancellationToken);
if (request == null)

View file

@ -406,6 +406,13 @@ namespace Ombi.Core.Engine.V2
mapped.Subscribed = viewMovie.Subscribed;
mapped.ShowSubscribe = viewMovie.ShowSubscribe;
mapped.DigitalReleaseDate = viewMovie.DigitalReleaseDate;
mapped.RequestedDate4k = viewMovie.RequestedDate4k;
mapped.Approved4K = viewMovie.Approved4K;
mapped.Available4K = viewMovie.Available4K;
mapped.Denied4K = viewMovie.Denied4K;
mapped.DeniedReason4K = viewMovie.DeniedReason4K;
mapped.Has4KRequest = viewMovie.Has4KRequest;
return mapped;
}

View file

@ -193,7 +193,7 @@ namespace Ombi.Core.Engine
case RequestType.Movie:
if (totalVotes >= voteSettings.MovieVoteMax)
{
result = await _movieRequestEngine.ApproveMovieById(requestId);
result = await _movieRequestEngine.ApproveMovieById(requestId, false);
}
break;
case RequestType.Album:

View file

@ -34,6 +34,8 @@ namespace Ombi.Core.Models.Requests
public int TheMovieDbId { get; set; }
public string LanguageCode { get; set; } = "en";
public bool Is4kRequest { get; set; }
/// <summary>
/// This is only set from a HTTP Header
/// </summary>

View file

@ -28,5 +28,14 @@ namespace Ombi.Core.Models.Search
public override RequestType Type => RequestType.Movie;
public ReleaseDatesDto ReleaseDates { get; set; }
public DateTime? DigitalReleaseDate { get; set; }
public bool Has4KRequest { get; set; }
public bool Approved4K { get; set; }
public DateTime MarkedAsApproved4K { get; set; }
public DateTime RequestedDate4k { get; set; }
public bool Available4K { get; set; }
public DateTime? MarkedAsAvailable4K { get; set; }
public bool? Denied4K { get; set; }
public DateTime MarkedAsDenied4K { get; set; }
public string DeniedReason4K { get; set; }
}
}

View file

@ -41,6 +41,15 @@ namespace Ombi.Core.Models.Search.V2
public Recommendations Recommendations { get; set; }
public ExternalIds ExternalIds { get; set; }
public Keywords Keywords { get; set; }
public bool Has4KRequest { get; set; }
public bool Approved4K { get; set; }
public DateTime MarkedAsApproved4K { get; set; }
public DateTime RequestedDate4k { get; set; }
public bool Available4K { get; set; }
public DateTime? MarkedAsAvailable4K { get; set; }
public bool? Denied4K { get; set; }
public DateTime MarkedAsDenied4K { get; set; }
public string DeniedReason4K { get; set; }
}
public class Keywords
{

View file

@ -5,7 +5,9 @@ using Microsoft.EntityFrameworkCore;
using Ombi.Core.Authentication;
using Ombi.Core.Models.Requests;
using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Services;
using Ombi.Helpers;
using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
@ -13,14 +15,16 @@ namespace Ombi.Core.Rule.Rules.Request
{
public class AutoApproveRule : BaseRequestRule, IRules<BaseRequest>
{
public AutoApproveRule(IPrincipal principal, OmbiUserManager um)
public AutoApproveRule(IPrincipal principal, OmbiUserManager um, IFeatureService featureService)
{
User = principal;
_manager = um;
_featureService = featureService;
}
private IPrincipal User { get; }
private readonly OmbiUserManager _manager;
private readonly IFeatureService _featureService;
public async Task<RuleResult> Execute(BaseRequest obj)
{
@ -28,17 +32,40 @@ namespace Ombi.Core.Rule.Rules.Request
var user = await _manager.Users.FirstOrDefaultAsync(x => x.NormalizedUserName == username);
if (await _manager.IsInRoleAsync(user, OmbiRoles.Admin) || user.IsSystemUser)
{
obj.Approved = true;
if (obj is MovieRequests movie)
{
await Check4K(movie);
}
else
{
obj.Approved = true;
}
return Success();
}
if (obj.RequestType == RequestType.Movie && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie))
obj.Approved = true;
{
var movie = (MovieRequests)obj;
await Check4K(movie);
}
if (obj.RequestType == RequestType.TvShow && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveTv))
obj.Approved = true;
if (obj.RequestType == RequestType.Album && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMusic))
obj.Approved = true;
return Success(); // We don't really care, we just don't set the obj to approve
}
private async Task Check4K(MovieRequests movie)
{
var featureEnabled = await _featureService.FeatureEnabled(FeatureNames.Movie4KRequests);
if (movie.Is4kRequest && featureEnabled)
{
movie.Approved4K = true;
}
else
{
movie.Approved = true;
}
}
}
}

View file

@ -33,8 +33,23 @@ namespace Ombi.Core.Rule.Rules.Request
if (obj.RequestType == RequestType.Movie)
{
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMovie) || await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie))
return Success();
var movie = (MovieRequests)obj;
var hasAutoApprove = await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie);
if (await _manager.IsInRoleAsync(user, OmbiRoles.RequestMovie) || hasAutoApprove)
{
if (movie.Is4kRequest && !hasAutoApprove)
{
var has4kPermission = await _manager.IsInRoleAsync(user, OmbiRoles.Request4KMovie);
if (has4kPermission)
{
return Success();
}
}
else
{
return Success();
}
}
return Fail(ErrorCode.NoPermissionsRequestMovie, "You do not have permissions to Request a Movie");
}

View file

@ -1,21 +1,24 @@
using System;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Rule.Interfaces;
using Ombi.Helpers;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository;
using Ombi.Core.Engine;
using Ombi.Store.Repository.Requests;
using Ombi.Core.Services;
using Ombi.Settings.Settings.Models;
namespace Ombi.Core.Rule.Rules.Request
{
public class ExistingMovieRequestRule : BaseRequestRule, IRules<BaseRequest>
{
public ExistingMovieRequestRule(IMovieRequestRepository movie)
private readonly IFeatureService _featureService;
public ExistingMovieRequestRule(IMovieRequestRepository movie, IFeatureService featureService)
{
Movie = movie;
_featureService = featureService;
}
private IMovieRequestRepository Movie { get; }
@ -35,7 +38,7 @@ namespace Ombi.Core.Rule.Rules.Request
var existing = await movieRequests.FirstOrDefaultAsync(x => x.TheMovieDbId == movie.TheMovieDbId);
if (existing != null) // Do we already have a request for this?
{
found = true;
found = await Check4KRequests(movie, existing);
}
if (!found && movie.ImdbId.HasValue())
@ -45,15 +48,30 @@ namespace Ombi.Core.Rule.Rules.Request
x.ImdbId == movie.ImdbId);
if (existing != null)
{
found = true;
found = await Check4KRequests(movie, existing);
}
}
if(found)
if (found)
{
return Fail(ErrorCode.AlreadyRequested, $"\"{obj.Title}\" has already been requested");
}
}
return Success();
}
private async Task<bool> Check4KRequests(MovieRequests movie, MovieRequests existing)
{
var featureEnabled = await _featureService.FeatureEnabled(FeatureNames.Movie4KRequests);
if (movie.Is4kRequest && existing.Has4KRequest && featureEnabled)
{
return true;
}
if (!movie.Is4kRequest && !existing.Has4KRequest || !featureEnabled)
{
return true;
}
return false;
}
}
}

View file

@ -63,11 +63,29 @@ namespace Ombi.Core.Rule.Rules.Search
}
}
}
if (item != null)
{
obj.Available = true;
obj.EmbyUrl = item.Url;
if (obj is SearchMovieViewModel movie)
{
if (item.Has4K)
{
movie.Available4K = true;
obj.EmbyUrl = item.Url;
}
if (item.Quality.HasValue())
{
obj.Available = true;
obj.EmbyUrl = item.Url;
obj.Quality = item.Quality;
}
}
else
{
obj.Available = true;
obj.EmbyUrl = item.Url;
}
if (obj.Type == RequestType.TvShow)
{

View file

@ -26,17 +26,27 @@ namespace Ombi.Core.Rule.Rules.Search
public async Task<RuleResult> Execute(SearchViewModel obj)
{
if (obj.Type == RequestType.Movie)
if (obj is SearchMovieViewModel movie)
{
var movieRequests = await Movie.GetRequestAsync(obj.Id);
if (movieRequests != null) // Do we already have a request for this?
{
obj.Requested = true;
obj.RequestId = movieRequests.Id;
obj.Approved = movieRequests.Approved;
obj.Denied = movieRequests.Denied ?? false;
obj.DeniedReason = movieRequests.DeniedReason;
obj.Available = movieRequests.Available;
// If the RequestDate is a min value, that means there's only a 4k request
movie.Requested = movieRequests.RequestedDate != DateTime.MinValue;
movie.RequestId = movieRequests.Id;
movie.Approved = movieRequests.Approved;
movie.Denied = movieRequests.Denied ?? false;
movie.DeniedReason = movieRequests.DeniedReason;
movie.Available = movieRequests.Available;
movie.Has4KRequest = movieRequests.Has4KRequest;
movie.RequestedDate4k = movieRequests.RequestedDate4k;
movie.Approved4K = movieRequests.Approved4K;
movie.Available4K = movieRequests.Available4K;
movie.Denied4K = movieRequests.Denied4K;
movie.DeniedReason4K = movieRequests.DeniedReason4K;
movie.MarkedAsApproved4K = movieRequests.MarkedAsApproved4K;
movie.MarkedAsAvailable4K = movieRequests.MarkedAsAvailable4K;
movie.MarkedAsDenied4K = movieRequests.MarkedAsDenied4K;
return Success();
}

View file

@ -80,8 +80,26 @@ namespace Ombi.Core.Rule.Rules.Search
obj.TheMovieDbId = obj.Id.ToString();
useTheMovieDb = true;
}
obj.Available = true;
obj.JellyfinUrl = item.Url;
if (obj is SearchMovieViewModel movie)
{
if (item.Has4K)
{
movie.Available4K = true;
obj.JellyfinUrl = item.Url;
}
if (item.Quality.HasValue())
{
obj.Available = true;
obj.EmbyUrl = item.Url;
obj.Quality = item.Quality;
}
}
else
{
obj.Available = true;
obj.JellyfinUrl = item.Url;
}
if (obj.Type == RequestType.TvShow)
{

View file

@ -89,7 +89,25 @@ namespace Ombi.Core.Rule.Rules.Search
obj.TheMovieDbId = obj.Id.ToString();
useTheMovieDb = true;
}
obj.Available = true;
if (obj is SearchMovieViewModel movie)
{
if (item.Has4K)
{
movie.Available4K = true;
}
if (item.Quality.HasValue())
{
obj.Available = true;
obj.Quality = item.Quality;
}
}
else
{
obj.Available = true;
}
if (item.Url.StartsWith("http"))
{
obj.PlexUrl = item.Url;
@ -99,11 +117,9 @@ namespace Ombi.Core.Rule.Rules.Search
// legacy content
obj.PlexUrl = PlexHelper.BuildPlexMediaUrl(item.Url, host);
}
obj.Quality = item.Quality;
if (obj.Type == RequestType.TvShow)
if (obj is SearchTvShowViewModel search)
{
var search = (SearchTvShowViewModel)obj;
// Let's go through the episodes now
if (search.SeasonRequests.Any())
{

View file

@ -18,16 +18,23 @@ namespace Ombi.Core.Rule.Rules.Search
public Task<RuleResult> Execute(SearchViewModel obj)
{
if (obj.Type == RequestType.Movie)
if (obj is SearchMovieViewModel movie)
{
// Check if it's in Radarr
var result = _db.GetAll().FirstOrDefault(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?
movie.Approved = true; // It's in radarr so it's approved... Maybe have a new property called "Processing" or something?
if (result.HasFile)
{
obj.Available = true;
if (result.Has4K)
{
movie.Available4K = true;
}
if (result.HasRegular)
{
movie.Available = true;
}
}
}
}

View file

@ -6,6 +6,6 @@ namespace Ombi.Core
{
public interface IMovieSender
{
Task<SenderResult> Send(MovieRequests model);
Task<SenderResult> Send(MovieRequests model, bool is4K);
}
}

View file

@ -20,13 +20,12 @@ namespace Ombi.Core.Senders
{
public class MovieSender : IMovieSender
{
public MovieSender(ISettingsService<RadarrSettings> radarrSettings, IRadarrApi api, ILogger<MovieSender> log,
public MovieSender(ISettingsService<RadarrSettings> radarrSettings, ISettingsService<Radarr4KSettings> radarr4kSettings, ILogger<MovieSender> log,
ISettingsService<DogNzbSettings> dogSettings, IDogNzbApi dogApi, ISettingsService<CouchPotatoSettings> cpSettings,
ICouchPotatoApi cpApi, IRepository<UserQualityProfiles> userProfiles, IRepository<RequestQueue> requestQueue, INotificationHelper notify,
IRadarrV3Api radarrV3Api)
{
_radarrSettings = radarrSettings;
_radarrV2Api = api;
_log = log;
_dogNzbSettings = dogSettings;
_dogNzbApi = dogApi;
@ -36,10 +35,11 @@ namespace Ombi.Core.Senders
_requestQueuRepository = requestQueue;
_notificationHelper = notify;
_radarrV3Api = radarrV3Api;
_radarr4KSettings = radarr4kSettings;
}
private readonly ISettingsService<RadarrSettings> _radarrSettings;
private readonly IRadarrApi _radarrV2Api;
private readonly ISettingsService<Radarr4KSettings> _radarr4KSettings;
private readonly ILogger<MovieSender> _log;
private readonly IDogNzbApi _dogNzbApi;
private readonly ISettingsService<DogNzbSettings> _dogNzbSettings;
@ -50,16 +50,24 @@ namespace Ombi.Core.Senders
private readonly INotificationHelper _notificationHelper;
private readonly IRadarrV3Api _radarrV3Api;
public async Task<SenderResult> Send(MovieRequests model)
public async Task<SenderResult> Send(MovieRequests model, bool is4K)
{
try
{
var cpSettings = await _couchPotatoSettings.GetSettingsAsync();
//var watcherSettings = await WatcherSettings.GetSettingsAsync();
var radarrSettings = await _radarrSettings.GetSettingsAsync();
RadarrSettings radarrSettings;
if (is4K)
{
radarrSettings = await _radarr4KSettings.GetSettingsAsync();
}
else
{
radarrSettings = await _radarrSettings.GetSettingsAsync();
}
if (radarrSettings.Enabled)
{
return await SendToRadarr(model, radarrSettings);
return await SendToRadarr(model, is4K, radarrSettings);
}
var dogSettings = await _dogNzbSettings.GetSettingsAsync();
@ -123,7 +131,7 @@ namespace Ombi.Core.Senders
return await _dogNzbApi.AddMovie(settings.ApiKey, id);
}
private async Task<SenderResult> SendToRadarr(MovieRequests model, RadarrSettings settings)
private async Task<SenderResult> SendToRadarr(MovieRequests model, bool is4K, RadarrSettings settings)
{
var qualityToUse = int.Parse(settings.DefaultQualityProfile);

View file

@ -0,0 +1,28 @@
using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models;
using System.Linq;
using System.Threading.Tasks;
namespace Ombi.Core.Services
{
public interface IFeatureService
{
Task<bool> FeatureEnabled(string featureName);
}
public class FeatureService : IFeatureService
{
private readonly ISettingsService<FeatureSettings> _featureSettings;
public FeatureService(ISettingsService<FeatureSettings> featureSettings)
{
_featureSettings = featureSettings;
}
public async Task<bool> FeatureEnabled(string featureName)
{
var settings = await _featureSettings.GetSettingsAsync();
return settings.Features?.Where(x => x.Name.Equals(featureName, System.StringComparison.InvariantCultureIgnoreCase)).Select(x => x.Enabled)?.FirstOrDefault() ?? false;
}
}
}