feat: Made a load of progress

radarr4k
tidusjar 3 years ago
parent 814c7f42c5
commit 645ea3b996

@ -83,7 +83,7 @@ namespace Ombi.Core.Tests.Engine
Assert.That(result.Result, Is.True);
VoteRepository.Verify(x => x.Add(It.Is<Votes>(c => c.UserId == "abc" && c.VoteType == type)), Times.Once);
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1, false), Times.Never);
}
public static IEnumerable<TestCaseData> VoteData
{
@ -129,7 +129,7 @@ namespace Ombi.Core.Tests.Engine
Assert.That(result.Result, Is.False);
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Never);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1, false), Times.Never);
}
public static IEnumerable<TestCaseData> AttemptedTwiceData
{
@ -175,7 +175,7 @@ namespace Ombi.Core.Tests.Engine
Assert.That(result.Result, Is.True);
VoteRepository.Verify(x => x.Delete(It.IsAny<Votes>()), Times.Once);
VoteRepository.Verify(x => x.Add(It.Is<Votes>(v => v.VoteType == type)), Times.Once);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1), Times.Never);
MovieRequestEngine.Verify(x => x.ApproveMovieById(1, false), Times.Never);
}
public static IEnumerable<TestCaseData> VoteConvertData
{

@ -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,

@ -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);
}
}

@ -72,7 +72,7 @@ namespace Ombi.Core.Engine
var userDetails = await GetUser();
var canRequestOnBehalf = model.RequestOnBehalf.HasValue();
var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser)
var isAdmin = await UserManager.IsInRoleAsync(userDetails, OmbiRoles.PowerUser)
|| await UserManager.IsInRoleAsync(userDetails, OmbiRoles.Admin);
if (canRequestOnBehalf && !isAdmin)
{
@ -94,28 +94,49 @@ namespace Ombi.Core.Engine
};
}
var requestModel = new MovieRequests
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)
{
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(),
Has4KRequest = model.Is4kRequest
};
if (model.Is4kRequest)
{
existingRequest.Has4KRequest = model.Is4kRequest;
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(),
Has4KRequest = model.Is4kRequest
};
}
var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US");
requestModel.DigitalReleaseDate = usDates?.ReleaseDate
@ -134,10 +155,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);
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);
@ -155,7 +176,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);
}
@ -510,13 +531,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)
@ -527,8 +548,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();
@ -542,7 +571,7 @@ namespace Ombi.Core.Engine
};
}
public async Task<RequestEngineResult> ApproveMovie(MovieRequests request)
public async Task<RequestEngineResult> ApproveMovie(MovieRequests request, bool is4K)
{
if (request == null)
{
@ -564,7 +593,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)
@ -592,11 +621,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
@ -664,7 +693,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
@ -685,7 +714,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)
@ -697,10 +726,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)
@ -711,7 +740,14 @@ namespace Ombi.Core.Engine
};
}
request.Available = false;
if (is4K)
{
request.Available4K = false;
}
else
{
request.Available = false;
}
await MovieRepository.Update(request);
await _mediaCacheService.Purge();
@ -722,7 +758,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)
@ -732,9 +768,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();
@ -746,9 +789,16 @@ 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)
{
await MovieRepository.Add(model);
if (!isExisting)
{
await MovieRepository.Add(model);
}
else
{
await MovieRepository.Update(model);
}
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, requestOnBehalf);
if (result.Success)

@ -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)

@ -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;
}

@ -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:

@ -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; }
}
}

@ -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
{

@ -28,12 +28,37 @@ 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.RequestType == RequestType.Movie)
{
var movie = (MovieRequests)obj;
if (movie.Has4KRequest)
{
movie.Approved4K = true;
}
if (movie.RequestedDate != DateTime.MinValue)
{
obj.Approved = true;
}
}
else
{
obj.Approved = true;
}
return Success();
}
if (obj.RequestType == RequestType.Movie && await _manager.IsInRoleAsync(user, OmbiRoles.AutoApproveMovie))
obj.Approved = true;
{
var movie = (MovieRequests)obj;
if (movie.Has4KRequest)
{
movie.Approved4K = true;
}
if (movie.RequestedDate != DateTime.MinValue)
{
obj.Approved = true;
}
}
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))

@ -28,15 +28,26 @@ namespace Ombi.Core.Rule.Rules.Search
{
if (obj.Type == RequestType.Movie)
{
var movie = (SearchMovieViewModel)obj;
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();
}

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

@ -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);

@ -49,7 +49,9 @@ namespace Ombi.Schedule.Jobs.Ombi
await _requestQueue.SaveChangesAsync();
continue;
}
var result = await _movieSender.Send(movieRequest);
// TODO probably need to add something to the request queue to better idenitfy if it's a 4k request
var result = await _movieSender.Send(movieRequest, movieRequest.Approved4K);
if (result.Success)
{
request.Completed = DateTime.UtcNow;

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using Newtonsoft.Json;
using System;
namespace Ombi.Store.Entities.Requests
{
@ -27,6 +28,16 @@ namespace Ombi.Store.Entities.Requests
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; }
/// <summary>
/// Only Use for setting the Language Code, Use the LanguageCode property for reading
/// </summary>

@ -0,0 +1,102 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Ombi.Store.Migrations.OmbiMySql
{
public partial class _4kMovieProperties : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Approved4K",
table: "MovieRequests",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "Available4K",
table: "MovieRequests",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "Denied4K",
table: "MovieRequests",
type: "tinyint(1)",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "DeniedReason4K",
table: "MovieRequests",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsApproved4K",
table: "MovieRequests",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsAvailable4K",
table: "MovieRequests",
type: "datetime(6)",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsDenied4K",
table: "MovieRequests",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "RequestedDate4k",
table: "MovieRequests",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Approved4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "Available4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "Denied4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "DeniedReason4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsApproved4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsAvailable4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsDenied4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "RequestedDate4k",
table: "MovieRequests");
}
}
}

@ -641,27 +641,39 @@ namespace Ombi.Store.Migrations.OmbiMySql
b.Property<bool>("Approved")
.HasColumnType("tinyint(1)");
b.Property<bool>("Approved4K")
.HasColumnType("tinyint(1)");
b.Property<bool>("Available")
.HasColumnType("tinyint(1)");
b.Property<bool>("Available4K")
.HasColumnType("tinyint(1)");
b.Property<string>("Background")
.HasColumnType("longtext");
b.Property<bool?>("Denied")
.HasColumnType("tinyint(1)");
b.Property<bool?>("Denied4K")
.HasColumnType("tinyint(1)");
b.Property<string>("DeniedReason")
.HasColumnType("longtext");
b.Property<string>("DeniedReason4K")
.HasColumnType("longtext");
b.Property<DateTime?>("DigitalReleaseDate")
.HasColumnType("datetime(6)");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<bool>("Has4KRequest")
.HasColumnType("tinyint(1)");
b.Property<string>("ImdbId")
.HasColumnType("longtext");
b.Property<int?>("IssueId")
.HasColumnType("int");
@ -671,12 +683,21 @@ namespace Ombi.Store.Migrations.OmbiMySql
b.Property<DateTime>("MarkedAsApproved")
.HasColumnType("datetime(6)");
b.Property<DateTime>("MarkedAsApproved4K")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("MarkedAsAvailable")
.HasColumnType("datetime(6)");
b.Property<DateTime?>("MarkedAsAvailable4K")
.HasColumnType("datetime(6)");
b.Property<DateTime>("MarkedAsDenied")
.HasColumnType("datetime(6)");
b.Property<DateTime>("MarkedAsDenied4K")
.HasColumnType("datetime(6)");
b.Property<string>("Overview")
.HasColumnType("longtext");
@ -698,6 +719,9 @@ namespace Ombi.Store.Migrations.OmbiMySql
b.Property<DateTime>("RequestedDate")
.HasColumnType("datetime(6)");
b.Property<DateTime>("RequestedDate4k")
.HasColumnType("datetime(6)");
b.Property<string>("RequestedUserId")
.HasColumnType("varchar(255)");

@ -0,0 +1,101 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Ombi.Store.Migrations.OmbiSqlite
{
public partial class _4kMovieProperties : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Approved4K",
table: "MovieRequests",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "Available4K",
table: "MovieRequests",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "Denied4K",
table: "MovieRequests",
type: "INTEGER",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "DeniedReason4K",
table: "MovieRequests",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsApproved4K",
table: "MovieRequests",
type: "TEXT",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsAvailable4K",
table: "MovieRequests",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "MarkedAsDenied4K",
table: "MovieRequests",
type: "TEXT",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "RequestedDate4k",
table: "MovieRequests",
type: "TEXT",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Approved4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "Available4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "Denied4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "DeniedReason4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsApproved4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsAvailable4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "MarkedAsDenied4K",
table: "MovieRequests");
migrationBuilder.DropColumn(
name: "RequestedDate4k",
table: "MovieRequests");
}
}
}

@ -639,27 +639,39 @@ namespace Ombi.Store.Migrations.OmbiSqlite
b.Property<bool>("Approved")
.HasColumnType("INTEGER");
b.Property<bool>("Approved4K")
.HasColumnType("INTEGER");
b.Property<bool>("Available")
.HasColumnType("INTEGER");
b.Property<bool>("Available4K")
.HasColumnType("INTEGER");
b.Property<string>("Background")
.HasColumnType("TEXT");
b.Property<bool?>("Denied")
.HasColumnType("INTEGER");
b.Property<bool?>("Denied4K")
.HasColumnType("INTEGER");
b.Property<string>("DeniedReason")
.HasColumnType("TEXT");
b.Property<DateTime?>("DigitalReleaseDate")
b.Property<string>("DeniedReason4K")
.HasColumnType("TEXT");
b.Property<string>("ImdbId")
b.Property<DateTime?>("DigitalReleaseDate")
.HasColumnType("TEXT");
b.Property<bool>("Has4KRequest")
.HasColumnType("INTEGER");
b.Property<string>("ImdbId")
.HasColumnType("TEXT");
b.Property<int?>("IssueId")
.HasColumnType("INTEGER");
@ -669,12 +681,21 @@ namespace Ombi.Store.Migrations.OmbiSqlite
b.Property<DateTime>("MarkedAsApproved")
.HasColumnType("TEXT");
b.Property<DateTime>("MarkedAsApproved4K")
.HasColumnType("TEXT");
b.Property<DateTime?>("MarkedAsAvailable")
.HasColumnType("TEXT");
b.Property<DateTime?>("MarkedAsAvailable4K")
.HasColumnType("TEXT");
b.Property<DateTime>("MarkedAsDenied")
.HasColumnType("TEXT");
b.Property<DateTime>("MarkedAsDenied4K")
.HasColumnType("TEXT");
b.Property<string>("Overview")
.HasColumnType("TEXT");
@ -696,6 +717,9 @@ namespace Ombi.Store.Migrations.OmbiSqlite
b.Property<DateTime>("RequestedDate")
.HasColumnType("TEXT");
b.Property<DateTime>("RequestedDate4k")
.HasColumnType("TEXT");
b.Property<string>("RequestedUserId")
.HasColumnType("TEXT");

@ -17,6 +17,10 @@ export interface IMovieRequests extends IFullBaseRequest {
showSubscribe: boolean;
requestStatus: string;
has4KRequest: boolean;
approved4K: boolean;
available4K: boolean;
denied4K: boolean;
deniedReason4K: string;
// For the UI
rootPathOverrideTitle: string;
@ -54,6 +58,7 @@ export interface IRequestsViewModel<T> {
export interface IMovieUpdateModel {
id: number;
is4K: boolean;
}
export interface IDenyMovieModel extends IMovieUpdateModel {

@ -42,6 +42,11 @@
externalIds: IExternalIds;
keywords: IKeywords;
belongsToCollection: ICollectionsModel;
has4KRequest: boolean;
approved4K: boolean;
available4K: boolean;
denied4K: boolean;
deniedReason4K: string;
// for the UI
requestProcessing: boolean;

@ -22,9 +22,11 @@
[isAdmin]="isAdmin"
[canShowAdvanced]="showAdvanced && movieRequest"
[type]="requestType"
[has4KRequest]="movie.has4KRequest"
(openTrailer)="openDialog()"
(onAdvancedOptions)="openAdvancedOptions()"
(onReProcessRequest)="reProcessRequest()"
(onReProcessRequest)="reProcessRequest(false)"
(onReProcess4KRequest)="reProcessRequest(true)"
>
</social-icons>
@ -54,6 +56,7 @@
<i class="far fa-play-circle fa-2x"></i>
</a>
</span>
<!-- Regular Movie Status -->
<button mat-raised-button class="btn-green btn-spacing" id="availableBtn" *ngIf="movie.available && !movie.plexUrl && !movie.embyUrl && !movie.jellyfinUrl"> {{
'Common.Available' | translate }}</button>
<span *ngIf="!movie.available">
@ -65,13 +68,34 @@
</button>
</ng-template>
<ng-template #notRequestedBtn>
<button *ngIf="!movie.requested" id="requestBtn" mat-raised-button class="btn-spacing" color="primary" (click)="request()">
<button *ngIf="!movie.requested" id="requestBtn" mat-raised-button class="btn-spacing" color="primary" (click)="request(false)">
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i>
<i *ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i>
{{'Common.Request' | translate }}
</button>
</ng-template>
</span>
<!-- 4k Status -->
<button mat-raised-button class="btn-green btn-spacing" id="availableBtn" *ngIf="movie.available4K && !movie.plexUrl && !movie.embyUrl && !movie.jellyfinUrl"> {{
'Common.Available' | translate }}</button>
<span *ngIf="!movie.available4K">
<span *ngIf="movie.has4KRequest || movie.approved4K; then requestedBtn4K else notRequestedBtn4K"></span>
<ng-template #requestedBtn4K>
<button id="requestedBtn4K" mat-raised-button *ngIf="!hasRequest || hasRequest && movieRequest && !movieRequest.denied4K" class="btn-spacing" color="warn" [disabled]>
<i class="fas fa-check"></i>
{{ 'Common.Requested4K' | translate }}
</button>
</ng-template>
<ng-template #notRequestedBtn4K>
<button *ngIf="!movie.has4KRequest" id="requestBtn4k" mat-raised-button class="btn-spacing" color="primary" (click)="request(true)">
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i>
<i *ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i>
{{'Common.Request4K' | translate }}
</button>
</ng-template>
<span *ngIf="!isAdmin && movie.showSubscribe" >
<button *ngIf="!movie.subscribed" (click)="notify()" id="notifyBtn" mat-raised-button class="btn-spacing" > <i class="fas fa-bell"></i>
{{ 'Requests.Notify' | translate }}</button>
@ -79,26 +103,45 @@
{{ 'Requests.RemoveNotification' | translate }}</button>
</span>
</span>
<span *ngIf="isAdmin && hasRequest">
<button id="approveBtn" *ngIf="!movie.approved " (click)="approve()" mat-raised-button class="btn-spacing" color="accent">
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
</button>
<button id="markAvailableBtn" *ngIf="!movie.available" (click)="markAvailable()" mat-raised-button class="btn-spacing"
color="accent">
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button>
<button id="markUnavailableBtn" *ngIf="movie.available" (click)="markUnavailable()" mat-raised-button class="btn-spacing"
color="accent">
<i class="fas fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}
</button>
<button id="denyBtn" *ngIf="movieRequest && !movieRequest.denied" mat-raised-button class="btn-spacing" color="warn" (click)="deny()">
<i class="fas fa-times"></i> {{'Requests.Deny' | translate }}
</button>
<button id="deniedButton" *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason" mat-raised-button class="btn-spacing" color="warn">
<i class="fas fa-times"></i> {{'MediaDetails.Denied' | translate }}
</button>
<button id="approveBtn" *ngIf="!movie.approved && movie.requested" (click)="approve(false)" mat-raised-button class="btn-spacing" color="accent">
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
</button>
<button id="approve4kBtn" *ngIf="!movie.approved4K && movie.has4KRequest " (click)="approve(true)" mat-raised-button class="btn-spacing" color="accent">
<i class="fas fa-plus"></i> {{ 'Common.Approve4K' | translate }}
</button>
<button id="markAvailableBtn" *ngIf="!movie.available" (click)="markAvailable(false)" mat-raised-button class="btn-spacing"
color="accent">
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button>
<button id="markAvailable4kBtn" *ngIf="!movie.available4K" (click)="markAvailable(true)" mat-raised-button class="btn-spacing"
color="accent">
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable4K' | translate }}
</button>
<button id="markUnavailableBtn" *ngIf="movie.available" (click)="markUnavailable(false)" mat-raised-button class="btn-spacing"
color="accent">
<i class="fas fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}
</button>
<button id="markUnavailable4kBtn" *ngIf="movie.available4K" (click)="markUnavailable(true)" mat-raised-button class="btn-spacing"
color="accent">
<i class="fas fa-minus"></i> {{ 'Requests.MarkUnavailable4K' | translate }}
</button>
<button id="denyBtn" *ngIf="!movieRequest.denied" mat-raised-button class="btn-spacing" color="warn" (click)="deny(false)">
<i class="fas fa-times"></i> {{'Requests.Deny' | translate }}
</button>
<button id="denyBtn4K" *ngIf="!movieRequest.denied4K" mat-raised-button class="btn-spacing" color="warn" (click)="deny(true)">
<i class="fas fa-times"></i> {{'Requests.Deny4K' | translate }}
</button>
<button id="deniedButton" *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason" mat-raised-button class="btn-spacing" color="warn">
<i class="fas fa-times"></i> {{'MediaDetails.Denied' | translate }}
</button>
<button id="deniedButton4k" *ngIf="movieRequest.denied4K" [matTooltip]="movieRequest.deniedReason4K" mat-raised-button class="btn-spacing" color="warn">
<i class="fas fa-times"></i> {{'MediaDetails.Denied4K' | translate }}
</button>
</span>
<button id="reportIssueBtn" mat-raised-button class="btn-spacing" color="danger" (click)="issue()" *ngIf="issuesEnabled">

@ -13,7 +13,7 @@ import { TranslateService } from "@ngx-translate/core";
import { MovieAdvancedOptionsComponent } from "./panels/movie-advanced-options/movie-advanced-options.component";
import { RequestServiceV2 } from "../../../services/requestV2.service";
import { RequestBehalfComponent } from "../shared/request-behalf/request-behalf.component";
import { forkJoin } from "rxjs";
import { firstValueFrom, forkJoin } from "rxjs";
import { AdminRequestDialogComponent } from "../../../shared/admin-request-dialog/admin-request-dialog.component";
@Component({
@ -86,18 +86,23 @@ export class MovieDetailsComponent {
}
}
public async request(userId?: string) {
public async request(is4K: boolean, userId?: string) {
if (this.isAdmin) {
const dialog = this.dialog.open(AdminRequestDialogComponent, { width: "700px", data: { type: RequestType.movie, id: this.movie.id }, panelClass: 'modal-panel' });
dialog.afterClosed().subscribe(async (result) => {
if (result) {
const requestResult = await this.requestService.requestMovie({ theMovieDbId: this.theMovidDbId,
const requestResult = await firstValueFrom(this.requestService.requestMovie({ theMovieDbId: this.theMovidDbId,
languageCode: this.translate.currentLang,
qualityPathOverride: result.radarrPathId,
requestOnBehalf: result.username?.id,
rootFolderOverride: result.radarrFolderId, }).toPromise();
rootFolderOverride: result.radarrFolderId,
is4KRequest: is4K }));
if (requestResult.result) {
this.movie.requested = true;
if (is4K) {
this.movie.has4KRequest = true;
} else {
this.movie.requested = true;
}
this.movie.requestId = requestResult.requestId;
this.messageService.send(this.translate.instant("Requests.RequestAddedSuccessfully", { title: this.movie.title }), "Ok");
this.movieRequest = await this.requestService.getMovieRequest(this.movie.requestId);
@ -107,7 +112,7 @@ export class MovieDetailsComponent {
}
});
} else {
const result = await this.requestService.requestMovie({ theMovieDbId: this.theMovidDbId, languageCode: this.translate.currentLang, requestOnBehalf: userId, qualityPathOverride: undefined, rootFolderOverride: undefined }).toPromise();
const result = await firstValueFrom(this.requestService.requestMovie({ theMovieDbId: this.theMovidDbId, languageCode: this.translate.currentLang, requestOnBehalf: userId, qualityPathOverride: undefined, rootFolderOverride: undefined, is4KRequest: is4K }));
if (result.result) {
this.movie.requested = true;
this.movie.requestId = result.requestId;
@ -149,21 +154,28 @@ export class MovieDetailsComponent {
});
}
public async approve() {
this.movie.approved = true;
const result = await this.requestService.approveMovie({ id: this.movieRequest.id }).toPromise();
public async approve(is4K: boolean) {
const result = await firstValueFrom(this.requestService.approveMovie({ id: this.movieRequest.id, is4K }));
if (result.result) {
if (is4K) {
this.movie.approved4K = true;
} else {
this.movie.approved = true;
}
this.messageService.send(this.translate.instant("Requests.SuccessfullyApproved"), "Ok");
} else {
this.movie.approved = false;
this.messageService.sendRequestEngineResultError(result);
}
}
public async markAvailable() {
const result = await this.requestService.markMovieAvailable({ id: this.movieRequest.id }).toPromise();
public async markAvailable(is4K: boolean) {
const result = await firstValueFrom(this.requestService.markMovieAvailable({ id: this.movieRequest.id, is4K }))
if (result.result) {
this.movie.available = true;
if (is4K) {
this.movie.available4K = true;
} else {
this.movie.available = true;
}
this.messageService.send(this.translate.instant("Requests.NowAvailable"), "Ok");
} else {
this.messageService.sendRequestEngineResultError(result);
@ -171,10 +183,14 @@ export class MovieDetailsComponent {
}
public async markUnavailable() {
const result = await this.requestService.markMovieUnavailable({ id: this.movieRequest.id }).toPromise();
public async markUnavailable(is4K: boolean) {
const result = await firstValueFrom(this.requestService.markMovieUnavailable({ id: this.movieRequest.id, is4K }));
if (result.result) {
this.movie.available = false;
if (is4K) {
this.movie.available4K = false;
} else {
this.movie.available = false;
}
this.messageService.send(this.translate.instant("Requests.NowUnavailable"), "Ok");
} else {
this.messageService.sendRequestEngineResultError(result);
@ -203,8 +219,8 @@ export class MovieDetailsComponent {
});
}
public reProcessRequest() {
this.requestService2.reprocessRequest(this.movieRequest.id, RequestType.movie).subscribe(result => {
public reProcessRequest(is4K: boolean) {
this.requestService2.reprocessRequest(this.movieRequest.id, RequestType.movie, is4K).subscribe(result => {
if (result.result) {
this.messageService.send(result.message ? result.message : this.translate.instant("Requests.SuccessfullyReprocessed"), "Ok");
} else {

@ -4,6 +4,7 @@ import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material/dialog";
import { RequestService, MessageService } from "../../../../services";
import { TranslateService } from "@ngx-translate/core";
import { RequestType, IRequestEngineResult } from "../../../../interfaces";
import { firstValueFrom } from "rxjs";
@Component({
selector: "deny-dialog",
@ -22,13 +23,13 @@ export class DenyDialogComponent {
public async deny() {
let result: IRequestEngineResult;
if(this.data.requestType == RequestType.movie) {
result = await this.requestService.denyMovie({id: this.data.requestId, reason: this.denyReason }).toPromise();
result = await firstValueFrom(this.requestService.denyMovie({id: this.data.requestId, reason: this.denyReason, is4K: this.data.is4K }));
}
if(this.data.requestType == RequestType.tvShow) {
result = await this.requestService.denyChild({id: this.data.requestId, reason: this.denyReason }).toPromise();
result = await firstValueFrom(this.requestService.denyChild({id: this.data.requestId, reason: this.denyReason }));
}
if(this.data.requestType == RequestType.album) {
result = await this.requestService.denyAlbum({id: this.data.requestId, reason: this.denyReason }).toPromise();
result = await firstValueFrom(this.requestService.denyAlbum({id: this.data.requestId, reason: this.denyReason }));
}
if (result.result) {

@ -4,6 +4,7 @@ export interface IDenyDialogData {
requestType: RequestType;
requestId: number;
denied: boolean;
is4K: boolean;
}
export interface IIssueDialogData {

@ -35,9 +35,13 @@
<span *ngIf="type === RequestType.movie"> {{ 'MediaDetails.RadarrConfiguration' | translate}}</span>
<span *ngIf="type === RequestType.tvShow"> {{ 'MediaDetails.SonarrConfiguration' | translate}}</span>
</button>
<button *ngIf="type === RequestType.movie" mat-menu-item (click)="reProcessRequest()">
<button *ngIf="type === RequestType.movie" mat-menu-item (click)="reProcessRequest(false)">
<i class="fas fa-sync icon-spacing"></i>
<span> {{ 'MediaDetails.ReProcessRequest' | translate}}</span>
</button>
<button *ngIf="type === RequestType.movie && has4KRequest" mat-menu-item (click)="reProcessRequest(true)">
<i class="fas fa-sync icon-spacing"></i>
<span> {{ 'MediaDetails.ReProcessRequest4K' | translate}}</span>
</button>
</mat-menu>
</div>

@ -23,10 +23,12 @@ export class SocialIconsComponent {
@Input() isAdmin: boolean;
@Input() canShowAdvanced: boolean;
@Input() has4KRequest: boolean;
@Output() openTrailer: EventEmitter<any> = new EventEmitter();
@Output() onAdvancedOptions: EventEmitter<any> = new EventEmitter();
@Output() onReProcessRequest: EventEmitter<any> = new EventEmitter();
@Output() onReProcess4KRequest: EventEmitter<any> = new EventEmitter();
public RequestType = RequestType;
@ -39,7 +41,11 @@ export class SocialIconsComponent {
this.onAdvancedOptions.emit();
}
public reProcessRequest() {
this.onReProcessRequest.emit();
public reProcessRequest(is4K: boolean) {
if (is4K) {
this.onReProcess4KRequest.emit();
} else {
this.onReProcessRequest.emit();
}
}
}

@ -100,7 +100,7 @@ export class TvRequestsPanelComponent {
}
public reProcessRequest(request: IChildRequests) {
this.requestService2.reprocessRequest(request.id, RequestType.tvShow).subscribe(result => {
this.requestService2.reprocessRequest(request.id, RequestType.tvShow, false).subscribe(result => {
if (result.result) {
this.messageService.send(result.message ? result.message : "Successfully Re-processed the request", "Ok");
} else {

@ -182,7 +182,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit {
}
let tasks = new Array<Observable<IRequestEngineResult>>();
this.selection.selected.forEach((selected) => {
tasks.push(this.requestServiceV1.approveMovie({ id: selected.id }));
tasks.push(this.requestServiceV1.approveMovie({ id: selected.id, is4K: false }));
});
this.isLoadingResults = true;

@ -4,7 +4,7 @@ import { MessageService, RequestService } from '../../../services';
import { IRequestEngineResult, RequestType } from '../../../interfaces';
import { UpdateType } from '../../models/UpdateType';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { firstValueFrom, Observable } from 'rxjs';
@Component({
selector: 'request-options',
@ -43,14 +43,15 @@ export class RequestOptionsComponent {
}
public async approve() {
// TODO 4K
if (this.data.type === RequestType.movie) {
await this.requestService.approveMovie({id: this.data.id}).toPromise();
await firstValueFrom(this.requestService.approveMovie({id: this.data.id, is4K: false}));
}
if (this.data.type === RequestType.tvShow) {
await this.requestService.approveChild({id: this.data.id}).toPromise();
await firstValueFrom(this.requestService.approveChild({id: this.data.id}));
}
if (this.data.type === RequestType.album) {
await this.requestService.approveAlbum({id: this.data.id}).toPromise();
await firstValueFrom(this.requestService.approveAlbum({id: this.data.id}));
}
this.bottomSheetRef.dismiss({type: UpdateType.Approve});
@ -59,10 +60,11 @@ export class RequestOptionsComponent {
public async changeAvailability() {
if (this.data.type === RequestType.movie) {
await this.requestService.markMovieAvailable({id: this.data.id}).toPromise();
// TODO 4K
await firstValueFrom(this.requestService.markMovieAvailable({id: this.data.id, is4K: false}))
}
if (this.data.type === RequestType.album) {
await this.requestService.markAlbumAvailable({id: this.data.id}).toPromise();
await firstValueFrom(this.requestService.markAlbumAvailable({id: this.data.id}));
}
this.bottomSheetRef.dismiss({type: UpdateType.Availability});

@ -93,8 +93,8 @@ export class RequestServiceV2 extends ServiceHelpers {
return this.http.post<IRequestEngineResult>(`${this.url}TV/`, JSON.stringify(tv), {headers: this.headers});
}
public reprocessRequest(requestId: number, type: RequestType): Observable<IRequestEngineResult> {
return this.http.post<IRequestEngineResult>(`${this.url}reprocess/${type}/${requestId}`, undefined, { headers: this.headers });
public reprocessRequest(requestId: number, type: RequestType, is4K: boolean): Observable<IRequestEngineResult> {
return this.http.post<IRequestEngineResult>(`${this.url}reprocess/${type}/${requestId}/${is4K}`, undefined, { headers: this.headers });
}
public requestMovieCollection(collectionId: number): Observable<IRequestEngineResult> {

@ -165,7 +165,7 @@ namespace Ombi.Controllers.V1
[PowerUser]
public async Task<RequestEngineResult> ApproveMovie([FromBody] MovieUpdateModel model)
{
return await MovieRequestEngine.ApproveMovieById(model.Id);
return await MovieRequestEngine.ApproveMovieById(model.Id, model.Is4K);
}
/// <summary>
@ -177,7 +177,7 @@ namespace Ombi.Controllers.V1
[PowerUser]
public async Task<RequestEngineResult> MarkMovieAvailable([FromBody] MovieUpdateModel model)
{
return await MovieRequestEngine.MarkAvailable(model.Id);
return await MovieRequestEngine.MarkAvailable(model.Id, model.Is4K);
}
/// <summary>
@ -189,7 +189,7 @@ namespace Ombi.Controllers.V1
[PowerUser]
public async Task<RequestEngineResult> MarkMovieUnAvailable([FromBody] MovieUpdateModel model)
{
return await MovieRequestEngine.MarkUnavailable(model.Id);
return await MovieRequestEngine.MarkUnavailable(model.Id, model.Is4K);
}
/// <summary>
@ -201,7 +201,7 @@ namespace Ombi.Controllers.V1
[PowerUser]
public async Task<RequestEngineResult> DenyMovie([FromBody] DenyMovieModel model)
{
return await MovieRequestEngine.DenyMovieById(model.Id, model.Reason);
return await MovieRequestEngine.DenyMovieById(model.Id, model.Reason, model.Is4K);
}
/// <summary>
@ -403,7 +403,7 @@ namespace Ombi.Controllers.V1
[PowerUser]
public async Task<RequestEngineResult> MarkTvAvailable([FromBody] TvUpdateModel model)
{
return await TvRequestEngine.MarkAvailable(model.Id);
return await TvRequestEngine.MarkAvailable(model.Id, false);
}
/// <summary>
@ -415,7 +415,7 @@ namespace Ombi.Controllers.V1
[PowerUser]
public async Task<RequestEngineResult> MarkTvUnAvailable([FromBody] TvUpdateModel model)
{
return await TvRequestEngine.MarkUnavailable(model.Id);
return await TvRequestEngine.MarkUnavailable(model.Id, false);
}
/// <summary>

@ -203,15 +203,15 @@ namespace Ombi.Controllers.V2
}
[PowerUser]
[HttpPost("reprocess/{type}/{requestId}")]
public async Task<IActionResult> ReProcessRequest(RequestType type, int requestId)
[HttpPost("reprocess/{type}/{requestId}/{is4K}")]
public async Task<IActionResult> ReProcessRequest(RequestType type, int requestId, bool? is4K)
{
switch (type)
{
case RequestType.TvShow:
return Ok(await _tvRequestEngine.ReProcessRequest(requestId, HttpContext.RequestAborted));
return Ok(await _tvRequestEngine.ReProcessRequest(requestId, false, HttpContext.RequestAborted));
case RequestType.Movie:
return Ok(await _movieRequestEngine.ReProcessRequest(requestId, HttpContext.RequestAborted));
return Ok(await _movieRequestEngine.ReProcessRequest(requestId, is4K ?? false, HttpContext.RequestAborted));
}
return BadRequest();

@ -29,5 +29,6 @@ namespace Ombi.Core.Models.Requests
public class MovieUpdateModel
{
public int Id { get; set; }
public bool Is4K { get; set; }
}
}

@ -95,6 +95,7 @@
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
<ProjectReference Include="..\Ombi.DependencyInjection\Ombi.DependencyInjection.csproj" />
<ProjectReference Include="..\Ombi.HealthChecks\Ombi.HealthChecks.csproj" />
<ProjectReference Include="..\Ombi.Helpers\Ombi.Helpers.csproj" />
<ProjectReference Include="..\Ombi.Hubs\Ombi.Hubs.csproj" />
<ProjectReference Include="..\Ombi.Mapping\Ombi.Mapping.csproj" />
<ProjectReference Include="..\Ombi.Schedule\Ombi.Schedule.csproj" />

@ -15,6 +15,7 @@
"ContinueButton": "Continue",
"Available": "Available",
"Approved": "Approved",
"Approve4K": "Approve 4K",
"Pending": "Pending",
"PartiallyAvailable": "Partially Available",
"Monitored": "Monitored",
@ -24,8 +25,10 @@
"RequestDenied": "Request Denied",
"NotRequested": "Not Requested",
"Requested": "Requested",
"Requested4K": "Requested 4K",
"Search":"Search",
"Request": "Request",
"Request4K": "Request 4K",
"Denied": "Denied",
"Approve": "Approve",
"PartlyAvailable": "Partly Available",
@ -161,9 +164,12 @@
"ChangeRootFolder": "Root Folder",
"ChangeQualityProfile": "Quality Profile",
"MarkUnavailable": "Mark Unavailable",
"MarkUnavailable4K": "Mark Unavailable 4K",
"MarkAvailable": "Mark Available",
"MarkAvailable4K": "Mark Available 4K",
"Remove": "Remove",
"Deny": "Deny",
"Deny4K": "Deny 4K",
"DenyReason": "Deny Reason",
"DeniedReason": "Denied Reason",
"Season": "Season",
@ -295,6 +301,7 @@
},
"MediaDetails": {
"Denied": "Denied",
"Denied4K": "Denied 4K",
"Trailers": "Trailers",
"RecommendationsTitle": "Recommendations",
"SimilarTitle": "Similar",
@ -363,6 +370,7 @@
"RequestDate": "Request Date:",
"DeniedReason": "Denied Reason:",
"ReProcessRequest": "Re-Process Request",
"ReProcessRequest4K": "Re-Process 4K Request",
"Music": {
"Type": "Type:",
"Country": "Country:",

Loading…
Cancel
Save