diff --git a/src/Ombi.Api.Lidarr/Models/Ratings.cs b/src/Ombi.Api.Lidarr/Models/Ratings.cs index 8260e6676..f2aac4203 100644 --- a/src/Ombi.Api.Lidarr/Models/Ratings.cs +++ b/src/Ombi.Api.Lidarr/Models/Ratings.cs @@ -3,6 +3,6 @@ public class Ratings { public int votes { get; set; } - public float value { get; set; } + public decimal value { get; set; } } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/Interfaces/IMusicSearchEngine.cs b/src/Ombi.Core/Engine/Interfaces/IMusicSearchEngine.cs index ca95246d0..44643bc9d 100644 --- a/src/Ombi.Core/Engine/Interfaces/IMusicSearchEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/IMusicSearchEngine.cs @@ -10,7 +10,7 @@ namespace Ombi.Core.Engine Task GetAlbumArtist(string foreignArtistId); Task GetArtist(int artistId); Task GetArtistAlbums(string foreignArtistId); - Task> SearchAlbum(string search); + Task> SearchAlbum(string search); Task> SearchArtist(string search); } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/MusicRequestEngine.cs b/src/Ombi.Core/Engine/MusicRequestEngine.cs index a99b98535..e30cd2f88 100644 --- a/src/Ombi.Core/Engine/MusicRequestEngine.cs +++ b/src/Ombi.Core/Engine/MusicRequestEngine.cs @@ -1,492 +1,492 @@ -using Ombi.Api.TheMovieDb; -using Ombi.Core.Models.Requests; -using Ombi.Helpers; -using Ombi.Store.Entities; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Security.Principal; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using Ombi.Api.Lidarr; -using Ombi.Api.TheMovieDb.Models; -using Ombi.Core.Authentication; -using Ombi.Core.Engine.Interfaces; -using Ombi.Core.Models.UI; -using Ombi.Core.Rule.Interfaces; -using Ombi.Core.Settings; -using Ombi.Settings.Settings.Models; -using Ombi.Settings.Settings.Models.External; -using Ombi.Store.Entities.Requests; -using Ombi.Store.Repository; - -namespace Ombi.Core.Engine -{ - public class MusicRequestEngine : BaseMediaEngine - { - public MusicRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user, - INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger log, - OmbiUserManager manager, IRepository rl, ICacheService cache, - ISettingsService ombiSettings, IRepository sub, ILidarrApi lidarr, - ISettingsService lidarrSettings) - : base(user, requestService, r, manager, cache, ombiSettings, sub) - { - MovieApi = movieApi; - NotificationHelper = helper; - Sender = sender; - Logger = log; - _requestLog = rl; - _lidarrApi = lidarr; - _lidarrSettings = lidarrSettings; - } - - private IMovieDbApi MovieApi { get; } - private INotificationHelper NotificationHelper { get; } - private IMovieSender Sender { get; } - private ILogger Logger { get; } - private readonly IRepository _requestLog; - private readonly ISettingsService _lidarrSettings; - private readonly ILidarrApi _lidarrApi; - - /// - /// Requests the movie. - /// - /// The model. - /// - public async Task RequestArtist(MusicArtistRequestViewModel model) - { - var s = await _lidarrSettings.GetSettingsAsync(); - var artist = await _lidarrApi.GetArtistByForignId(model.ForeignArtistId, s.ApiKey, s.FullUri); - if (artist == null) - { - return new RequestEngineResult - { - Result = false, - Message = "There was an issue adding this Artist!", - ErrorMessage = "Please try again later" - }; - } +//using Ombi.Api.TheMovieDb; +//using Ombi.Core.Models.Requests; +//using Ombi.Helpers; +//using Ombi.Store.Entities; +//using System; +//using System.Collections.Generic; +//using System.Globalization; +//using System.Linq; +//using System.Security.Principal; +//using System.Threading.Tasks; +//using Microsoft.EntityFrameworkCore; +//using Microsoft.Extensions.Logging; +//using Ombi.Api.Lidarr; +//using Ombi.Api.TheMovieDb.Models; +//using Ombi.Core.Authentication; +//using Ombi.Core.Engine.Interfaces; +//using Ombi.Core.Models.UI; +//using Ombi.Core.Rule.Interfaces; +//using Ombi.Core.Settings; +//using Ombi.Settings.Settings.Models; +//using Ombi.Settings.Settings.Models.External; +//using Ombi.Store.Entities.Requests; +//using Ombi.Store.Repository; + +//namespace Ombi.Core.Engine +//{ +// public class MusicRequestEngine : BaseMediaEngine +// { +// public MusicRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user, +// INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger log, +// OmbiUserManager manager, IRepository rl, ICacheService cache, +// ISettingsService ombiSettings, IRepository sub, ILidarrApi lidarr, +// ISettingsService lidarrSettings) +// : base(user, requestService, r, manager, cache, ombiSettings, sub) +// { +// MovieApi = movieApi; +// NotificationHelper = helper; +// Sender = sender; +// Logger = log; +// _requestLog = rl; +// _lidarrApi = lidarr; +// _lidarrSettings = lidarrSettings; +// } + +// private IMovieDbApi MovieApi { get; } +// private INotificationHelper NotificationHelper { get; } +// private IMovieSender Sender { get; } +// private ILogger Logger { get; } +// private readonly IRepository _requestLog; +// private readonly ISettingsService _lidarrSettings; +// private readonly ILidarrApi _lidarrApi; + +// /// +// /// Requests the movie. +// /// +// /// The model. +// /// +// public async Task RequestArtist(MusicArtistRequestViewModel model) +// { +// var s = await _lidarrSettings.GetSettingsAsync(); +// var artist = await _lidarrApi.GetArtistByForignId(model.ForeignArtistId, s.ApiKey, s.FullUri); +// if (artist == null) +// { +// return new RequestEngineResult +// { +// Result = false, +// Message = "There was an issue adding this Artist!", +// ErrorMessage = "Please try again later" +// }; +// } - var userDetails = await GetUser(); - - var 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 = DateTime.UtcNow, - Approved = false, - RequestedUserId = userDetails.Id, - Background = movieInfo.BackdropPath - }; - - var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US"); - requestModel.DigitalReleaseDate = usDates?.ReleaseDate - ?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate; - - var ruleResults = (await RunRequestRules(requestModel)).ToList(); - if (ruleResults.Any(x => !x.Success)) - { - return new RequestEngineResult - { - ErrorMessage = ruleResults.FirstOrDefault(x => x.Message.HasValue()).Message - }; - } - - if (requestModel.Approved) // The rules have auto approved this - { - var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName); - if (requestEngineResult.Result) - { - var result = await ApproveMovie(requestModel); - if (result.IsError) - { - Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); - return new RequestEngineResult - { - Message = result.Message, - ErrorMessage = result.Message, - Result = false - }; - } - - return requestEngineResult; - } - - // If there are no providers then it's successful but movie has not been sent - } - - return await AddMovieRequest(requestModel, fullMovieName); - } - - - /// - /// Gets the requests. - /// - /// The count. - /// The position. - /// The order/filter type. - /// - public async Task> GetRequests(int count, int position, - OrderFilterModel orderFilter) - { - var shouldHide = await HideFromOtherUsers(); - IQueryable allRequests; - if (shouldHide.Hide) - { - allRequests = - MovieRepository.GetWithUser(shouldHide - .UserId); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); - } - else - { - allRequests = - MovieRepository - .GetWithUser(); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); - } - - switch (orderFilter.AvailabilityFilter) - { - case FilterType.None: - break; - case FilterType.Available: - allRequests = allRequests.Where(x => x.Available); - break; - case FilterType.NotAvailable: - allRequests = allRequests.Where(x => !x.Available); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - switch (orderFilter.StatusFilter) - { - case FilterType.None: - break; - case FilterType.Approved: - allRequests = allRequests.Where(x => x.Approved); - break; - case FilterType.Processing: - allRequests = allRequests.Where(x => x.Approved && !x.Available); - break; - case FilterType.PendingApproval: - allRequests = allRequests.Where(x => !x.Approved && !x.Available && !(x.Denied ?? false)); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - var total = allRequests.Count(); - - var requests = await (OrderMovies(allRequests, orderFilter.OrderType)).Skip(position).Take(count) - .ToListAsync(); - - requests.ForEach(async x => - { - x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); - await CheckForSubscription(shouldHide, x); - }); - return new RequestsViewModel - { - Collection = requests, - Total = total - }; - } - - private IQueryable OrderMovies(IQueryable allRequests, OrderType type) - { - switch (type) - { - case OrderType.RequestedDateAsc: - return allRequests.OrderBy(x => x.RequestedDate); - case OrderType.RequestedDateDesc: - return allRequests.OrderByDescending(x => x.RequestedDate); - case OrderType.TitleAsc: - return allRequests.OrderBy(x => x.Title); - case OrderType.TitleDesc: - return allRequests.OrderByDescending(x => x.Title); - case OrderType.StatusAsc: - return allRequests.OrderBy(x => x.Status); - case OrderType.StatusDesc: - return allRequests.OrderByDescending(x => x.Status); - default: - throw new ArgumentOutOfRangeException(nameof(type), type, null); - } - } - - public async Task GetTotal() - { - var shouldHide = await HideFromOtherUsers(); - if (shouldHide.Hide) - { - return await MovieRepository.GetWithUser(shouldHide.UserId).CountAsync(); - } - else - { - return await MovieRepository.GetWithUser().CountAsync(); - } - } - - /// - /// Gets the requests. - /// - /// - public async Task> GetRequests() - { - var shouldHide = await HideFromOtherUsers(); - List allRequests; - if (shouldHide.Hide) - { - allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync(); - } - else - { - allRequests = await MovieRepository.GetWithUser().ToListAsync(); - } - - allRequests.ForEach(async x => - { - x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); - await CheckForSubscription(shouldHide, x); - }); - return allRequests; - } - - private async Task CheckForSubscription(HideResult shouldHide, MovieRequests x) - { - if (shouldHide.UserId == x.RequestedUserId) - { - x.ShowSubscribe = false; - } - else - { - x.ShowSubscribe = true; - var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s => - s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.Movie); - x.Subscribed = sub != null; - } - } - - /// - /// Searches the movie request. - /// - /// The search. - /// - public async Task> SearchMovieRequest(string search) - { - var shouldHide = await HideFromOtherUsers(); - List allRequests; - if (shouldHide.Hide) - { - allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync(); - } - else - { - allRequests = await MovieRepository.GetWithUser().ToListAsync(); - } - - var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList(); - results.ForEach(async x => - { - x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); - await CheckForSubscription(shouldHide, x); - }); - return results; - } - - public async Task ApproveMovieById(int requestId) - { - var request = await MovieRepository.Find(requestId); - return await ApproveMovie(request); - } - - public async Task DenyMovieById(int modelId) - { - var request = await MovieRepository.Find(modelId); - if (request == null) - { - return new RequestEngineResult - { - ErrorMessage = "Request does not exist" - }; - } - - request.Denied = true; - // We are denying a request - NotificationHelper.Notify(request, NotificationType.RequestDeclined); - await MovieRepository.Update(request); - - return new RequestEngineResult - { - Message = "Request successfully deleted", - }; - } - - public async Task ApproveMovie(MovieRequests request) - { - if (request == null) - { - return new RequestEngineResult - { - ErrorMessage = "Request does not exist" - }; - } - - request.Approved = true; - request.Denied = false; - await MovieRepository.Update(request); - - var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification); - if (canNotify.Success) - { - NotificationHelper.Notify(request, NotificationType.RequestApproved); - } - - if (request.Approved) - { - var result = await Sender.Send(request); - if (result.Success && result.Sent) - { - return new RequestEngineResult - { - Result = true - }; - } - - if (!result.Success) - { - Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); - return new RequestEngineResult - { - Message = result.Message, - ErrorMessage = result.Message, - Result = false - }; - } - - // If there are no providers then it's successful but movie has not been sent - } - - return new RequestEngineResult - { - Result = true - }; - } - - /// - /// Updates the movie request. - /// - /// The request. - /// - public async Task UpdateMovieRequest(MovieRequests request) - { - var allRequests = await MovieRepository.GetWithUser().ToListAsync(); - var results = allRequests.FirstOrDefault(x => x.Id == request.Id); - - results.Approved = request.Approved; - results.Available = request.Available; - results.Denied = request.Denied; - results.DeniedReason = request.DeniedReason; - results.ImdbId = request.ImdbId; - results.IssueId = request.IssueId; - results.Issues = request.Issues; - results.Overview = request.Overview; - results.PosterPath = PosterPathHelper.FixPosterPath(request.PosterPath); - results.QualityOverride = request.QualityOverride; - results.RootPathOverride = request.RootPathOverride; - - await MovieRepository.Update(results); - return results; - } - - /// - /// Removes the movie request. - /// - /// The request identifier. - /// - public async Task RemoveMovieRequest(int requestId) - { - var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId); - await MovieRepository.Delete(request); - } - - public async Task UserHasRequest(string userId) - { - return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId); - } - - public async Task MarkUnavailable(int modelId) - { - var request = await MovieRepository.Find(modelId); - if (request == null) - { - return new RequestEngineResult - { - ErrorMessage = "Request does not exist" - }; - } - - request.Available = false; - await MovieRepository.Update(request); - - return new RequestEngineResult - { - Message = "Request is now unavailable", - Result = true - }; - } - - public async Task MarkAvailable(int modelId) - { - var request = await MovieRepository.Find(modelId); - if (request == null) - { - return new RequestEngineResult - { - ErrorMessage = "Request does not exist" - }; - } - - request.Available = true; - request.MarkedAsAvailable = DateTime.Now; - NotificationHelper.Notify(request, NotificationType.RequestAvailable); - await MovieRepository.Update(request); - - return new RequestEngineResult - { - Message = "Request is now available", - Result = true - }; - } - - private async Task AddMovieRequest(MovieRequests model, string movieName) - { - await MovieRepository.Add(model); - - var result = await RunSpecificRule(model, SpecificRules.CanSendNotification); - if (result.Success) - { - NotificationHelper.NewRequest(model); - } - - await _requestLog.Add(new RequestLog - { - UserId = (await GetUser()).Id, - RequestDate = DateTime.UtcNow, - RequestId = model.Id, - RequestType = RequestType.Movie, - }); - - return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!"}; - } - } -} \ No newline at end of file +// var userDetails = await GetUser(); + +// var 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 = DateTime.UtcNow, +// Approved = false, +// RequestedUserId = userDetails.Id, +// Background = movieInfo.BackdropPath +// }; + +// var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US"); +// requestModel.DigitalReleaseDate = usDates?.ReleaseDate +// ?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate; + +// var ruleResults = (await RunRequestRules(requestModel)).ToList(); +// if (ruleResults.Any(x => !x.Success)) +// { +// return new RequestEngineResult +// { +// ErrorMessage = ruleResults.FirstOrDefault(x => x.Message.HasValue()).Message +// }; +// } + +// if (requestModel.Approved) // The rules have auto approved this +// { +// var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName); +// if (requestEngineResult.Result) +// { +// var result = await ApproveMovie(requestModel); +// if (result.IsError) +// { +// Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); +// return new RequestEngineResult +// { +// Message = result.Message, +// ErrorMessage = result.Message, +// Result = false +// }; +// } + +// return requestEngineResult; +// } + +// // If there are no providers then it's successful but movie has not been sent +// } + +// return await AddMovieRequest(requestModel, fullMovieName); +// } + + +// /// +// /// Gets the requests. +// /// +// /// The count. +// /// The position. +// /// The order/filter type. +// /// +// public async Task> GetRequests(int count, int position, +// OrderFilterModel orderFilter) +// { +// var shouldHide = await HideFromOtherUsers(); +// IQueryable allRequests; +// if (shouldHide.Hide) +// { +// allRequests = +// MovieRepository.GetWithUser(shouldHide +// .UserId); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); +// } +// else +// { +// allRequests = +// MovieRepository +// .GetWithUser(); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); +// } + +// switch (orderFilter.AvailabilityFilter) +// { +// case FilterType.None: +// break; +// case FilterType.Available: +// allRequests = allRequests.Where(x => x.Available); +// break; +// case FilterType.NotAvailable: +// allRequests = allRequests.Where(x => !x.Available); +// break; +// default: +// throw new ArgumentOutOfRangeException(); +// } + +// switch (orderFilter.StatusFilter) +// { +// case FilterType.None: +// break; +// case FilterType.Approved: +// allRequests = allRequests.Where(x => x.Approved); +// break; +// case FilterType.Processing: +// allRequests = allRequests.Where(x => x.Approved && !x.Available); +// break; +// case FilterType.PendingApproval: +// allRequests = allRequests.Where(x => !x.Approved && !x.Available && !(x.Denied ?? false)); +// break; +// default: +// throw new ArgumentOutOfRangeException(); +// } + +// var total = allRequests.Count(); + +// var requests = await (OrderMovies(allRequests, orderFilter.OrderType)).Skip(position).Take(count) +// .ToListAsync(); + +// requests.ForEach(async x => +// { +// x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); +// await CheckForSubscription(shouldHide, x); +// }); +// return new RequestsViewModel +// { +// Collection = requests, +// Total = total +// }; +// } + +// private IQueryable OrderMovies(IQueryable allRequests, OrderType type) +// { +// switch (type) +// { +// case OrderType.RequestedDateAsc: +// return allRequests.OrderBy(x => x.RequestedDate); +// case OrderType.RequestedDateDesc: +// return allRequests.OrderByDescending(x => x.RequestedDate); +// case OrderType.TitleAsc: +// return allRequests.OrderBy(x => x.Title); +// case OrderType.TitleDesc: +// return allRequests.OrderByDescending(x => x.Title); +// case OrderType.StatusAsc: +// return allRequests.OrderBy(x => x.Status); +// case OrderType.StatusDesc: +// return allRequests.OrderByDescending(x => x.Status); +// default: +// throw new ArgumentOutOfRangeException(nameof(type), type, null); +// } +// } + +// public async Task GetTotal() +// { +// var shouldHide = await HideFromOtherUsers(); +// if (shouldHide.Hide) +// { +// return await MovieRepository.GetWithUser(shouldHide.UserId).CountAsync(); +// } +// else +// { +// return await MovieRepository.GetWithUser().CountAsync(); +// } +// } + +// /// +// /// Gets the requests. +// /// +// /// +// public async Task> GetRequests() +// { +// var shouldHide = await HideFromOtherUsers(); +// List allRequests; +// if (shouldHide.Hide) +// { +// allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync(); +// } +// else +// { +// allRequests = await MovieRepository.GetWithUser().ToListAsync(); +// } + +// allRequests.ForEach(async x => +// { +// x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); +// await CheckForSubscription(shouldHide, x); +// }); +// return allRequests; +// } + +// private async Task CheckForSubscription(HideResult shouldHide, MovieRequests x) +// { +// if (shouldHide.UserId == x.RequestedUserId) +// { +// x.ShowSubscribe = false; +// } +// else +// { +// x.ShowSubscribe = true; +// var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s => +// s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.Movie); +// x.Subscribed = sub != null; +// } +// } + +// /// +// /// Searches the movie request. +// /// +// /// The search. +// /// +// public async Task> SearchMovieRequest(string search) +// { +// var shouldHide = await HideFromOtherUsers(); +// List allRequests; +// if (shouldHide.Hide) +// { +// allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync(); +// } +// else +// { +// allRequests = await MovieRepository.GetWithUser().ToListAsync(); +// } + +// var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList(); +// results.ForEach(async x => +// { +// x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); +// await CheckForSubscription(shouldHide, x); +// }); +// return results; +// } + +// public async Task ApproveMovieById(int requestId) +// { +// var request = await MovieRepository.Find(requestId); +// return await ApproveMovie(request); +// } + +// public async Task DenyMovieById(int modelId) +// { +// var request = await MovieRepository.Find(modelId); +// if (request == null) +// { +// return new RequestEngineResult +// { +// ErrorMessage = "Request does not exist" +// }; +// } + +// request.Denied = true; +// // We are denying a request +// NotificationHelper.Notify(request, NotificationType.RequestDeclined); +// await MovieRepository.Update(request); + +// return new RequestEngineResult +// { +// Message = "Request successfully deleted", +// }; +// } + +// public async Task ApproveMovie(MovieRequests request) +// { +// if (request == null) +// { +// return new RequestEngineResult +// { +// ErrorMessage = "Request does not exist" +// }; +// } + +// request.Approved = true; +// request.Denied = false; +// await MovieRepository.Update(request); + +// var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification); +// if (canNotify.Success) +// { +// NotificationHelper.Notify(request, NotificationType.RequestApproved); +// } + +// if (request.Approved) +// { +// var result = await Sender.Send(request); +// if (result.Success && result.Sent) +// { +// return new RequestEngineResult +// { +// Result = true +// }; +// } + +// if (!result.Success) +// { +// Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); +// return new RequestEngineResult +// { +// Message = result.Message, +// ErrorMessage = result.Message, +// Result = false +// }; +// } + +// // If there are no providers then it's successful but movie has not been sent +// } + +// return new RequestEngineResult +// { +// Result = true +// }; +// } + +// /// +// /// Updates the movie request. +// /// +// /// The request. +// /// +// public async Task UpdateMovieRequest(MovieRequests request) +// { +// var allRequests = await MovieRepository.GetWithUser().ToListAsync(); +// var results = allRequests.FirstOrDefault(x => x.Id == request.Id); + +// results.Approved = request.Approved; +// results.Available = request.Available; +// results.Denied = request.Denied; +// results.DeniedReason = request.DeniedReason; +// results.ImdbId = request.ImdbId; +// results.IssueId = request.IssueId; +// results.Issues = request.Issues; +// results.Overview = request.Overview; +// results.PosterPath = PosterPathHelper.FixPosterPath(request.PosterPath); +// results.QualityOverride = request.QualityOverride; +// results.RootPathOverride = request.RootPathOverride; + +// await MovieRepository.Update(results); +// return results; +// } + +// /// +// /// Removes the movie request. +// /// +// /// The request identifier. +// /// +// public async Task RemoveMovieRequest(int requestId) +// { +// var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId); +// await MovieRepository.Delete(request); +// } + +// public async Task UserHasRequest(string userId) +// { +// return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId); +// } + +// public async Task MarkUnavailable(int modelId) +// { +// var request = await MovieRepository.Find(modelId); +// if (request == null) +// { +// return new RequestEngineResult +// { +// ErrorMessage = "Request does not exist" +// }; +// } + +// request.Available = false; +// await MovieRepository.Update(request); + +// return new RequestEngineResult +// { +// Message = "Request is now unavailable", +// Result = true +// }; +// } + +// public async Task MarkAvailable(int modelId) +// { +// var request = await MovieRepository.Find(modelId); +// if (request == null) +// { +// return new RequestEngineResult +// { +// ErrorMessage = "Request does not exist" +// }; +// } + +// request.Available = true; +// request.MarkedAsAvailable = DateTime.Now; +// NotificationHelper.Notify(request, NotificationType.RequestAvailable); +// await MovieRepository.Update(request); + +// return new RequestEngineResult +// { +// Message = "Request is now available", +// Result = true +// }; +// } + +// private async Task AddMovieRequest(MovieRequests model, string movieName) +// { +// await MovieRepository.Add(model); + +// var result = await RunSpecificRule(model, SpecificRules.CanSendNotification); +// if (result.Success) +// { +// NotificationHelper.NewRequest(model); +// } + +// await _requestLog.Add(new RequestLog +// { +// UserId = (await GetUser()).Id, +// RequestDate = DateTime.UtcNow, +// RequestId = model.Id, +// RequestType = RequestType.Movie, +// }); + +// return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!"}; +// } +// } +//} \ No newline at end of file diff --git a/src/Ombi.Core/Engine/MusicSearchEngine.cs b/src/Ombi.Core/Engine/MusicSearchEngine.cs index 63c3eed77..ebb396d99 100644 --- a/src/Ombi.Core/Engine/MusicSearchEngine.cs +++ b/src/Ombi.Core/Engine/MusicSearchEngine.cs @@ -47,12 +47,17 @@ namespace Ombi.Core.Engine /// /// The search. /// - public async Task> SearchAlbum(string search) + public async Task> SearchAlbum(string search) { var settings = await GetSettings(); var result = await _lidarrApi.AlbumLookup(search, settings.ApiKey, settings.FullUri); + var vm = new List(); + foreach (var r in result) + { + vm.Add(await MapIntoAlbumVm(r, settings)); + } - return result; + return vm; } /// @@ -74,30 +79,6 @@ namespace Ombi.Core.Engine return vm; } - private SearchArtistViewModel MapIntoArtistVm(ArtistLookup a) - { - var vm = new SearchArtistViewModel - { - ArtistName = a.artistName, - ArtistType = a.artistType, - Banner = a.images?.FirstOrDefault(x => x.coverType.Equals("banner"))?.url, - Logo = a.images?.FirstOrDefault(x => x.coverType.Equals("logo"))?.url, - CleanName = a.cleanName, - Disambiguation = a.disambiguation, - ForignArtistId = a.foreignArtistId, - Links = a.links, - Overview = a.overview, - }; - - var poster = a.images?.FirstOrDefault(x => x.coverType.Equals("poaster")); - if (poster == null) - { - vm.Poster = a.remotePoster; - } - - return vm; - } - /// /// Returns all albums by the specified artist /// @@ -126,7 +107,62 @@ namespace Ombi.Core.Engine return await _lidarrApi.GetArtist(artistId, settings.ApiKey, settings.FullUri); } + private SearchArtistViewModel MapIntoArtistVm(ArtistLookup a) + { + var vm = new SearchArtistViewModel + { + ArtistName = a.artistName, + ArtistType = a.artistType, + Banner = a.images?.FirstOrDefault(x => x.coverType.Equals("banner"))?.url, + Logo = a.images?.FirstOrDefault(x => x.coverType.Equals("logo"))?.url, + CleanName = a.cleanName, + Disambiguation = a.disambiguation, + ForignArtistId = a.foreignArtistId, + Links = a.links, + Overview = a.overview, + }; + + var poster = a.images?.FirstOrDefault(x => x.coverType.Equals("poaster")); + if (poster == null) + { + vm.Poster = a.remotePoster; + } + return vm; + } + + private async Task MapIntoAlbumVm(AlbumLookup a, LidarrSettings settings) + { + var vm = new SearchAlbumViewModel + { + ForeignAlbumId = a.foreignAlbumId, + Monitored = a.monitored, + Rating = a.ratings?.value ?? 0m, + ReleaseDate = a.releaseDate, + Title = a.title + }; + if (vm.Monitored) + { + // The JSON is different for some stupid reason + // Need to lookup the artist now and all the images -.-" + var artist = await _lidarrApi.GetArtist(a.artistId, settings.ApiKey, settings.FullUri); + vm.ArtistName = artist.artistName; + vm.ForeignArtistId = artist.foreignArtistId; + } + else + { + vm.ForeignArtistId = a.artist?.foreignArtistId; + vm.ArtistName = a.artist?.artistName; + } + + vm.Cover = a.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url; + if (vm.Cover == null) + { + vm.Cover = a.remoteCover; + } + + return vm; + } private LidarrSettings _settings; private async Task GetSettings() { diff --git a/src/Ombi.Core/Models/Search/SearchAlbumViewModel.cs b/src/Ombi.Core/Models/Search/SearchAlbumViewModel.cs new file mode 100644 index 000000000..b243c5374 --- /dev/null +++ b/src/Ombi.Core/Models/Search/SearchAlbumViewModel.cs @@ -0,0 +1,19 @@ +using System; + +namespace Ombi.Core.Models.Search +{ + public class SearchAlbumViewModel + { + public string Title { get; set; } + public string ForeignAlbumId { get; set; } + public bool Monitored { get; set; } + public string AlbumType { get; set; } + public decimal Rating { get; set; } + public DateTime ReleaseDate { get; set; } + public string ArtistName { get; set; } + public string ForeignArtistId { get; set; } + public string Cover { get; set; } + public string Disk { get; set; } + + } +} \ No newline at end of file diff --git a/src/Ombi.Store/Entities/Requests/ArtistRequest.cs b/src/Ombi.Store/Entities/Requests/ArtistRequest.cs deleted file mode 100644 index 84f82694f..000000000 --- a/src/Ombi.Store/Entities/Requests/ArtistRequest.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ombi.Store.Entities.Requests -{ - public class ArtistRequest : BaseRequest - { - public string ArtistName { get; set; } - public string ForignArtistId { get; set; } - public string Overview { get; set; } - public string Disambiguation { get; set; } - public string Banner { get; set; } - public string Poster { get; set; } - public string Logo { get; set; } - public bool Monitored { get; set; } - public string ArtistType { get; set; } - public string CleanName { get; set; } - } -} \ No newline at end of file diff --git a/src/Ombi/ClientApp/app/interfaces/ISearchMusicResult.ts b/src/Ombi/ClientApp/app/interfaces/ISearchMusicResult.ts index ecf705f0e..4c16ac88b 100644 --- a/src/Ombi/ClientApp/app/interfaces/ISearchMusicResult.ts +++ b/src/Ombi/ClientApp/app/interfaces/ISearchMusicResult.ts @@ -1,5 +1,7 @@ export interface ISearchArtistResult { artistName: string; + artistType: string; + disambiguation: string; forignArtistId: string; banner: string; @@ -10,6 +12,7 @@ requested: boolean; requestId: number; available: boolean; + links: ILink[]; subscribed: boolean; showSubscribe: boolean; @@ -19,3 +22,30 @@ processed: boolean; background: any; } + +export interface ILink { + url: string; + name: string; +} + +export interface ISearchAlbumResult { + albumType: string; + artistName: string; + cover: string; + disk: string; + foreignAlbumId: string; + foreignArtistId: string; + monitored: boolean; + rating: number; + releaseDate: Date; + title: string; + approved: boolean; + requested: boolean; + requestId: number; + available: boolean; + + // for the UI + requestProcessing: boolean; + processed: boolean; + background: any; +} diff --git a/src/Ombi/ClientApp/app/search/music/albumsearch.component.html b/src/Ombi/ClientApp/app/search/music/albumsearch.component.html new file mode 100644 index 000000000..bb8d304b2 --- /dev/null +++ b/src/Ombi/ClientApp/app/search/music/albumsearch.component.html @@ -0,0 +1,77 @@ +
+ +
+
+
+ poster + +
+
+ +

{{result.overview | truncate: 350 }}

+
+ + +
+
+
+ + +
+
+
+ +
+
+
+ + + + + + +
+ + +
+ + + +
+ +
\ No newline at end of file diff --git a/src/Ombi/ClientApp/app/search/music/albumsearch.component.ts b/src/Ombi/ClientApp/app/search/music/albumsearch.component.ts new file mode 100644 index 000000000..99f27f08f --- /dev/null +++ b/src/Ombi/ClientApp/app/search/music/albumsearch.component.ts @@ -0,0 +1,63 @@ +import { Component, Input } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; + +import { AuthService } from "../../auth/auth.service"; +import { IRequestEngineResult, ISearchMovieResult } from "../../interfaces"; +import { ISearchAlbumResult } from "../../interfaces/ISearchMusicResult"; +import { NotificationService, RequestService } from "../../services"; + +@Component({ + selector: "album-search", + templateUrl: "./albumsearch.component.html", +}) +export class AlbumSearchComponent { + + @Input() public result: ISearchAlbumResult; + public engineResult: IRequestEngineResult; + @Input() public defaultPoster: string; + + constructor( + private requestService: RequestService, + private notificationService: NotificationService, private authService: AuthService, + private readonly translate: TranslateService) { + } + + public request(searchResult: ISearchMovieResult) { + searchResult.requested = true; + searchResult.requestProcessing = true; + searchResult.showSubscribe = false; + if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) { + searchResult.approved = true; + } + + try { + this.requestService.requestMovie({ theMovieDbId: searchResult.id }) + .subscribe(x => { + this.engineResult = x; + + if (this.engineResult.result) { + this.translate.get("Search.RequestAdded", { title: searchResult.title }).subscribe(x => { + this.notificationService.success(x); + searchResult.processed = true; + }); + } else { + if (this.engineResult.errorMessage && this.engineResult.message) { + this.notificationService.warning("Request Added", `${this.engineResult.message} - ${this.engineResult.errorMessage}`); + } else { + this.notificationService.warning("Request Added", this.engineResult.message ? this.engineResult.message : this.engineResult.errorMessage); + } + searchResult.requested = false; + searchResult.approved = false; + searchResult.processed = false; + searchResult.requestProcessing = false; + + } + }); + } catch (e) { + + searchResult.processed = false; + searchResult.requestProcessing = false; + this.notificationService.error(e); + } + } +} diff --git a/src/Ombi/ClientApp/app/search/music/artistsearch.component.html b/src/Ombi/ClientApp/app/search/music/artistsearch.component.html new file mode 100644 index 000000000..b68990d69 --- /dev/null +++ b/src/Ombi/ClientApp/app/search/music/artistsearch.component.html @@ -0,0 +1,65 @@ +
+ +
+
+
+ poster + +
+
+
+ +

{{result.artistName}}

+
+ + + + + {{result.artistType}} + + + {{result.disambiguation}} + + + Monitored + + + +
+
+

{{result.overview | truncate: 350 }}

+ + +
+ +
+
+
+ + +
+
+ + +
+ + +
+ + + + +
\ No newline at end of file diff --git a/src/Ombi/ClientApp/app/search/music/artistsearch.component.ts b/src/Ombi/ClientApp/app/search/music/artistsearch.component.ts new file mode 100644 index 000000000..8794d5efc --- /dev/null +++ b/src/Ombi/ClientApp/app/search/music/artistsearch.component.ts @@ -0,0 +1,63 @@ +import { Component, Input } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; + +import { AuthService } from "../../auth/auth.service"; +import { IRequestEngineResult, ISearchMovieResult } from "../../interfaces"; +import { ISearchArtistResult } from "../../interfaces/ISearchMusicResult"; +import { NotificationService, RequestService } from "../../services"; + +@Component({ + selector: "artist-search", + templateUrl: "./artistsearch.component.html", +}) +export class ArtistSearchComponent { + + @Input() public result: ISearchArtistResult; + public engineResult: IRequestEngineResult; + @Input() public defaultPoster: string; + + constructor( + private requestService: RequestService, + private notificationService: NotificationService, private authService: AuthService, + private readonly translate: TranslateService) { + } + + public request(searchResult: ISearchMovieResult) { + searchResult.requested = true; + searchResult.requestProcessing = true; + searchResult.showSubscribe = false; + if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) { + searchResult.approved = true; + } + + try { + this.requestService.requestMovie({ theMovieDbId: searchResult.id }) + .subscribe(x => { + this.engineResult = x; + + if (this.engineResult.result) { + this.translate.get("Search.RequestAdded", { title: searchResult.title }).subscribe(x => { + this.notificationService.success(x); + searchResult.processed = true; + }); + } else { + if (this.engineResult.errorMessage && this.engineResult.message) { + this.notificationService.warning("Request Added", `${this.engineResult.message} - ${this.engineResult.errorMessage}`); + } else { + this.notificationService.warning("Request Added", this.engineResult.message ? this.engineResult.message : this.engineResult.errorMessage); + } + searchResult.requested = false; + searchResult.approved = false; + searchResult.processed = false; + searchResult.requestProcessing = false; + + } + }); + } catch (e) { + + searchResult.processed = false; + searchResult.requestProcessing = false; + this.notificationService.error(e); + } + } +} diff --git a/src/Ombi/ClientApp/app/search/music/musicsearch.component.html b/src/Ombi/ClientApp/app/search/music/musicsearch.component.html index 347864be8..28ea1b399 100644 --- a/src/Ombi/ClientApp/app/search/music/musicsearch.component.html +++ b/src/Ombi/ClientApp/app/search/music/musicsearch.component.html @@ -6,93 +6,36 @@ +
+
+ + + + +
+
+ +

-
-
+
+
+
+
- -
- -
-
-
- poster - -
-
-
- -

{{result.artistName}}

-
- - - - - - - - - - - -
-
-

{{result.overview | truncate: 350 }}

-
- - -
-
-
- - -
-
-
- -
-
-
- - - - - - -
- - -
- - - -
- -
+

+
+ +
+
+
diff --git a/src/Ombi/ClientApp/app/search/music/musicsearch.component.ts b/src/Ombi/ClientApp/app/search/music/musicsearch.component.ts index 4007b5b9a..546fde9f6 100644 --- a/src/Ombi/ClientApp/app/search/music/musicsearch.component.ts +++ b/src/Ombi/ClientApp/app/search/music/musicsearch.component.ts @@ -7,7 +7,7 @@ import { debounceTime, distinctUntilChanged } from "rxjs/operators"; import { AuthService } from "../../auth/auth.service"; import { IIssueCategory, IRequestEngineResult, ISearchMovieResult } from "../../interfaces"; -import { ISearchArtistResult } from "../../interfaces/ISearchMusicResult"; +import { ISearchAlbumResult, ISearchArtistResult } from "../../interfaces/ISearchMusicResult"; import { NotificationService, RequestService, SearchService } from "../../services"; @Component({ @@ -19,6 +19,7 @@ export class MusicSearchComponent implements OnInit { public searchText: string; public searchChanged: Subject = new Subject(); public artistResult: ISearchArtistResult[]; + public albumResult: ISearchAlbumResult[]; public result: IRequestEngineResult; public searchApplied = false; public searchAlbum: boolean; @@ -35,9 +36,8 @@ export class MusicSearchComponent implements OnInit { constructor( private searchService: SearchService, private requestService: RequestService, private notificationService: NotificationService, private authService: AuthService, - private readonly translate: TranslateService, - private readonly platformLocation: PlatformLocation, - private sanitizer: DomSanitizer) { + private readonly translate: TranslateService, private sanitizer: DomSanitizer, + private readonly platformLocation: PlatformLocation) { this.searchChanged.pipe( debounceTime(600), // Wait Xms after the last event before emitting last event @@ -45,22 +45,27 @@ export class MusicSearchComponent implements OnInit { ).subscribe(x => { this.searchText = x as string; if (this.searchText === "") { - this.clearResults(); + if(this.searchAlbum) { + this.clearAlbumResults(); + } else { + this.clearArtistResults(); + } + return; } if(this.searchAlbum) { this.searchService.searchAlbum(this.searchText) .subscribe(x => { - this.artistResult = x; + this.albumResult = x; this.searchApplied = true; - this.setBackground(); + this.setAlbumBackground(); }); } else { this.searchService.searchArtist(this.searchText) .subscribe(x => { this.artistResult = x; this.searchApplied = true; - this.setBackground(); + this.setArtistBackground(); }); } }); @@ -85,6 +90,16 @@ export class MusicSearchComponent implements OnInit { this.searchChanged.next(text.target.value); } + public searchMode(val: boolean) { + this.searchAlbum = val; + if(val) { + // Album + this.clearArtistResults(); + } else { + this.clearAlbumResults(); + } + } + public request(searchResult: ISearchMovieResult) { searchResult.requested = true; searchResult.requestProcessing = true; @@ -124,18 +139,31 @@ export class MusicSearchComponent implements OnInit { } } - private clearResults() { + private clearArtistResults() { this.artistResult = []; this.searchApplied = false; } - private setBackground() { + private clearAlbumResults() { + this.albumResult = []; + this.searchApplied = false; + } + + private setArtistBackground() { this.artistResult.forEach((val, index) => { if (val.poster === null) { val.poster = this.defaultPoster; - } + } val.background = this.sanitizer.bypassSecurityTrustStyle ("url(" + val.banner + ")"); }); } + + private setAlbumBackground() { + this.albumResult.forEach((val, index) => { + if (val.cover === null) { + val.cover = this.defaultPoster; + } + }); + } } diff --git a/src/Ombi/ClientApp/app/search/search.module.ts b/src/Ombi/ClientApp/app/search/search.module.ts index 3e8181807..7e72dba77 100644 --- a/src/Ombi/ClientApp/app/search/search.module.ts +++ b/src/Ombi/ClientApp/app/search/search.module.ts @@ -7,6 +7,8 @@ import { NgbModule } from "@ng-bootstrap/ng-bootstrap"; import { MovieSearchComponent } from "./moviesearch.component"; import { MovieSearchGridComponent } from "./moviesearchgrid.component"; +import { AlbumSearchComponent } from "./music/albumsearch.component"; +import { ArtistSearchComponent } from "./music/artistsearch.component"; import { MusicSearchComponent } from "./music/musicsearch.component"; import { SearchComponent } from "./search.component"; import { SeriesInformationComponent } from "./seriesinformation.component"; @@ -43,6 +45,8 @@ const routes: Routes = [ SeriesInformationComponent, MovieSearchGridComponent, MusicSearchComponent, + ArtistSearchComponent, + AlbumSearchComponent, ], exports: [ RouterModule, diff --git a/src/Ombi/ClientApp/app/shared/shared.module.ts b/src/Ombi/ClientApp/app/shared/shared.module.ts index 08b46aed4..b87c3f42d 100644 --- a/src/Ombi/ClientApp/app/shared/shared.module.ts +++ b/src/Ombi/ClientApp/app/shared/shared.module.ts @@ -6,7 +6,7 @@ import { TruncateModule } from "@yellowspot/ng-truncate"; import { IssuesReportComponent } from "./issues-report.component"; -import { SidebarModule } from "primeng/primeng"; +import { InputSwitchModule, SidebarModule } from "primeng/primeng"; @NgModule({ declarations: [ @@ -16,6 +16,7 @@ import { SidebarModule } from "primeng/primeng"; SidebarModule, FormsModule, CommonModule, + InputSwitchModule, TruncateModule, ], exports: [ @@ -25,6 +26,7 @@ import { SidebarModule } from "primeng/primeng"; SidebarModule, IssuesReportComponent, TruncateModule, + InputSwitchModule, ], }) export class SharedModule {} diff --git a/src/Ombi/ClientApp/styles/base.scss b/src/Ombi/ClientApp/styles/base.scss index 7bd29aaaa..593511316 100644 --- a/src/Ombi/ClientApp/styles/base.scss +++ b/src/Ombi/ClientApp/styles/base.scss @@ -990,4 +990,17 @@ a > h4:hover { .modal-footer .btn+.btn { margin-left: 5px; margin-bottom: 10px; +} + +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: normal; + vertical-align: baseline; + border-radius: .25em; } \ No newline at end of file diff --git a/src/Ombi/Controllers/SearchController.cs b/src/Ombi/Controllers/SearchController.cs index c528293e7..026e4541d 100644 --- a/src/Ombi/Controllers/SearchController.cs +++ b/src/Ombi/Controllers/SearchController.cs @@ -202,7 +202,7 @@ namespace Ombi.Controllers /// We use Lidarr as the Provider /// [HttpGet("music/album/{searchTerm}")] - public async Task> SearchAlbum(string searchTerm) + public async Task> SearchAlbum(string searchTerm) { return await MusicEngine.SearchAlbum(searchTerm); }