mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-13 16:52:56 -07:00
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:
parent
09f648515e
commit
ba88848866
153 changed files with 12438 additions and 784 deletions
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue