Improved the UI !wip

pull/2478/head
TidusJar 6 years ago
parent 83537e2a36
commit 33fdffdd0f

@ -3,6 +3,6 @@
public class Ratings
{
public int votes { get; set; }
public float value { get; set; }
public decimal value { get; set; }
}
}

@ -10,7 +10,7 @@ namespace Ombi.Core.Engine
Task<ArtistResult> GetAlbumArtist(string foreignArtistId);
Task<ArtistResult> GetArtist(int artistId);
Task<ArtistResult> GetArtistAlbums(string foreignArtistId);
Task<IEnumerable<AlbumLookup>> SearchAlbum(string search);
Task<IEnumerable<SearchAlbumViewModel>> SearchAlbum(string search);
Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string search);
}
}

@ -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<MovieRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr,
ISettingsService<LidarrSettings> 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<MovieRequestEngine> Logger { get; }
private readonly IRepository<RequestLog> _requestLog;
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private readonly ILidarrApi _lidarrApi;
/// <summary>
/// Requests the movie.
/// </summary>
/// <param name="model">The model.</param>
/// <returns></returns>
public async Task<RequestEngineResult> 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<MovieRequestEngine> log,
// OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
// ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr,
// ISettingsService<LidarrSettings> 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<MovieRequestEngine> Logger { get; }
// private readonly IRepository<RequestLog> _requestLog;
// private readonly ISettingsService<LidarrSettings> _lidarrSettings;
// private readonly ILidarrApi _lidarrApi;
// /// <summary>
// /// Requests the movie.
// /// </summary>
// /// <param name="model">The model.</param>
// /// <returns></returns>
// public async Task<RequestEngineResult> 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);
}
/// <summary>
/// Gets the requests.
/// </summary>
/// <param name="count">The count.</param>
/// <param name="position">The position.</param>
/// <param name="orderFilter">The order/filter type.</param>
/// <returns></returns>
public async Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position,
OrderFilterModel orderFilter)
{
var shouldHide = await HideFromOtherUsers();
IQueryable<MovieRequests> 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<MovieRequests>
{
Collection = requests,
Total = total
};
}
private IQueryable<MovieRequests> OrderMovies(IQueryable<MovieRequests> 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<int> GetTotal()
{
var shouldHide = await HideFromOtherUsers();
if (shouldHide.Hide)
{
return await MovieRepository.GetWithUser(shouldHide.UserId).CountAsync();
}
else
{
return await MovieRepository.GetWithUser().CountAsync();
}
}
/// <summary>
/// Gets the requests.
/// </summary>
/// <returns></returns>
public async Task<IEnumerable<MovieRequests>> GetRequests()
{
var shouldHide = await HideFromOtherUsers();
List<MovieRequests> 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;
}
}
/// <summary>
/// Searches the movie request.
/// </summary>
/// <param name="search">The search.</param>
/// <returns></returns>
public async Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search)
{
var shouldHide = await HideFromOtherUsers();
List<MovieRequests> 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<RequestEngineResult> ApproveMovieById(int requestId)
{
var request = await MovieRepository.Find(requestId);
return await ApproveMovie(request);
}
public async Task<RequestEngineResult> 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<RequestEngineResult> 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
};
}
/// <summary>
/// Updates the movie request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns></returns>
public async Task<MovieRequests> 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;
}
/// <summary>
/// Removes the movie request.
/// </summary>
/// <param name="requestId">The request identifier.</param>
/// <returns></returns>
public async Task RemoveMovieRequest(int requestId)
{
var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
await MovieRepository.Delete(request);
}
public async Task<bool> UserHasRequest(string userId)
{
return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
}
public async Task<RequestEngineResult> 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<RequestEngineResult> 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<RequestEngineResult> 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!"};
}
}
}
// 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);
// }
// /// <summary>
// /// Gets the requests.
// /// </summary>
// /// <param name="count">The count.</param>
// /// <param name="position">The position.</param>
// /// <param name="orderFilter">The order/filter type.</param>
// /// <returns></returns>
// public async Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position,
// OrderFilterModel orderFilter)
// {
// var shouldHide = await HideFromOtherUsers();
// IQueryable<MovieRequests> 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<MovieRequests>
// {
// Collection = requests,
// Total = total
// };
// }
// private IQueryable<MovieRequests> OrderMovies(IQueryable<MovieRequests> 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<int> GetTotal()
// {
// var shouldHide = await HideFromOtherUsers();
// if (shouldHide.Hide)
// {
// return await MovieRepository.GetWithUser(shouldHide.UserId).CountAsync();
// }
// else
// {
// return await MovieRepository.GetWithUser().CountAsync();
// }
// }
// /// <summary>
// /// Gets the requests.
// /// </summary>
// /// <returns></returns>
// public async Task<IEnumerable<MovieRequests>> GetRequests()
// {
// var shouldHide = await HideFromOtherUsers();
// List<MovieRequests> 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;
// }
// }
// /// <summary>
// /// Searches the movie request.
// /// </summary>
// /// <param name="search">The search.</param>
// /// <returns></returns>
// public async Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search)
// {
// var shouldHide = await HideFromOtherUsers();
// List<MovieRequests> 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<RequestEngineResult> ApproveMovieById(int requestId)
// {
// var request = await MovieRepository.Find(requestId);
// return await ApproveMovie(request);
// }
// public async Task<RequestEngineResult> 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<RequestEngineResult> 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
// };
// }
// /// <summary>
// /// Updates the movie request.
// /// </summary>
// /// <param name="request">The request.</param>
// /// <returns></returns>
// public async Task<MovieRequests> 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;
// }
// /// <summary>
// /// Removes the movie request.
// /// </summary>
// /// <param name="requestId">The request identifier.</param>
// /// <returns></returns>
// public async Task RemoveMovieRequest(int requestId)
// {
// var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
// await MovieRepository.Delete(request);
// }
// public async Task<bool> UserHasRequest(string userId)
// {
// return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
// }
// public async Task<RequestEngineResult> 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<RequestEngineResult> 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<RequestEngineResult> 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!"};
// }
// }
//}

@ -47,12 +47,17 @@ namespace Ombi.Core.Engine
/// </summary>
/// <param name="search">The search.</param>
/// <returns></returns>
public async Task<IEnumerable<AlbumLookup>> SearchAlbum(string search)
public async Task<IEnumerable<SearchAlbumViewModel>> SearchAlbum(string search)
{
var settings = await GetSettings();
var result = await _lidarrApi.AlbumLookup(search, settings.ApiKey, settings.FullUri);
var vm = new List<SearchAlbumViewModel>();
foreach (var r in result)
{
vm.Add(await MapIntoAlbumVm(r, settings));
}
return result;
return vm;
}
/// <summary>
@ -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;
}
/// <summary>
/// Returns all albums by the specified artist
/// </summary>
@ -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<SearchAlbumViewModel> 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<LidarrSettings> GetSettings()
{

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

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

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

@ -0,0 +1,77 @@
<div class="row" >
<div class="myBg backdrop" [style.background-image]="result.background"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<div class="col-sm-3 small-padding">
<img *ngIf="result.cover" class="img-responsive poster" src="{{result.cover}}" alt="poster">
</div>
<div class="col-sm-7 small-padding">
<div>
<a href="" target="_blank">
<h4>{{result.title}}</h4>
</a>
<a href="" target="_blank">
<h4>{{result.artistName}}</h4>
</a>
<span class="tags">
<!-- <span *ngIf="result.releaseDate" class="label label-info" id="releaseDateLabel" target="_blank">{{ 'Search.TheatricalRelease' | translate: {date: result.releaseDate | date: 'mediumDate'} }}</span>
<span *ngIf="result.digitalReleaseDate" class="label label-info" id="releaseDateLabel" target="_blank">{{ 'Search.DigitalDate' | translate: {date: result.digitalReleaseDate | date: 'mediumDate'} }}</span>
<a *ngIf="result.homepage" href="{{result.homepage}}" id="homePageLabel" target="_blank"><span class="label label-info" [translate]="'Search.Movies.HomePage'"></span></a>
<a *ngIf="result.trailer" href="{{result.trailer}}" id="trailerLabel" target="_blank"><span class="label label-info" [translate]="'Search.Movies.Trailer'"></span></a> -->
<ng-template [ngIf]="result.available"><span class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span></ng-template>
<ng-template [ngIf]="result.approved && !result.available"><span class="label label-info" id="processingRequestLabel" [translate]="'Common.ProcessingRequest'"></span></ng-template>
<ng-template [ngIf]="result.requested && !result.approved && !result.available"><span class="label label-warning" id="pendingApprovalLabel" [translate]="'Common.PendingApproval'"></span></ng-template>
<ng-template [ngIf]="!result.requested && !result.available && !result.approved"><span class="label label-danger" id="notRequestedLabel" [translate]="'Common.NotRequested'"></span></ng-template>
</span>
<br/>
</div>
<p style="font-size: 0.9rem !important">{{result.overview | truncate: 350 }}</p>
</div>
<div class="col-sm-2 small-padding">
<div class="row" *ngIf="result.requested">
<div class="col-md-2 col-md-push-10">
<!-- <a *ngIf="result.showSubscribe && !result.subscribed" style="color:white" (click)="subscribe(result)" pTooltip="Subscribe for notifications"> <i class="fa fa-rss"></i></a>
<a *ngIf="result.showSubscribe && result.subscribed" style="color:red" (click)="unSubscribe(result)" pTooltip="Unsubscribe notification"> <i class="fa fa-rss"></i></a> -->
</div>
</div>
<div *ngIf="result.available">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> {{ 'Common.Available' | translate }}</button>
</div>
<div *ngIf="!result.available">
<div *ngIf="result.requested || result.approved; then requestedBtn else notRequestedBtn"></div>
<ng-template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> {{ 'Common.Requested' | translate }}</button>
</ng-template>
<ng-template #notRequestedBtn>
<button style="text-align: right" class="btn btn-primary-outline" (click)="request(result)">
<i *ngIf="result.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i> <i *ngIf="!result.requestProcessing && !result.processed" class="fa fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fa fa-check"></i> {{ 'Common.Request' | translate }}</button>
</ng-template>
</div>
<!-- <button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)"> <i class="fa fa-eye"></i> {{ 'Search.Similar' | translate }}</button> -->
<br/>
<div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> Report Issue
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<!-- <li *ngFor="let cat of issueCategories"><a [routerLink]="" (click)="reportIssue(cat, result)">{{cat.value}}</a></li> -->
</ul>
</div>
</div>
</div>

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

@ -0,0 +1,65 @@
<div class="row">
<div class="myBg backdrop" [style.background-image]="result.background"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<div class="col-sm-3 small-padding">
<img *ngIf="result.poster" class="img-responsive poster" src="{{result.poster}}" alt="poster">
</div>
<div class="col-sm-7 small-padding">
<div>
<a href="" target="_blank">
<h4>{{result.artistName}}</h4>
</a>
<span class="tags">
<!-- <span *ngIf="result.releaseDate" class="label label-info" id="releaseDateLabel" target="_blank">{{ 'Search.TheatricalRelease' | translate: {date: result.releaseDate | date: 'mediumDate'} }}</span>
<span *ngIf="result.digitalReleaseDate" class="label label-info" id="releaseDateLabel" target="_blank">{{ 'Search.DigitalDate' | translate: {date: result.digitalReleaseDate | date: 'mediumDate'} }}</span>
<a *ngIf="result.homepage" href="{{result.homepage}}" id="homePageLabel" target="_blank"><span class="label label-info" [translate]="'Search.Movies.HomePage'"></span></a>
<a *ngIf="result.trailer" href="{{result.trailer}}" id="trailerLabel" target="_blank"><span class="label label-info" [translate]="'Search.Movies.Trailer'"></span></a> -->
<ng-template [ngIf]="result.artistType">
<span class="label label-info" id="artistType">{{result.artistType}}</span>
</ng-template>
<ng-template [ngIf]="result.disambiguation">
<span class="label label-info" id="disambiguation">{{result.disambiguation}}</span>
</ng-template>
<ng-template [ngIf]="result.monitored">
<span class="label label-info" id="disambiguation">Monitored</span>
</ng-template>
</span>
<br/>
</div>
<p style="font-size: 0.9rem !important">{{result.overview | truncate: 350 }}</p>
<div class="row">
<a id="infoTags" *ngFor="let link of result.links" href="{{link.url}}" target="_blank" class="label label-primary">
{{link.name}}
</a>
</div>
</div>
<div class="col-sm-2 small-padding">
<div class="row" *ngIf="result.requested">
<div class="col-md-2 col-md-push-10">
<!-- <a *ngIf="result.showSubscribe && !result.subscribed" style="color:white" (click)="subscribe(result)" pTooltip="Subscribe for notifications"> <i class="fa fa-rss"></i></a>
<a *ngIf="result.showSubscribe && result.subscribed" style="color:red" (click)="unSubscribe(result)" pTooltip="Unsubscribe notification"> <i class="fa fa-rss"></i></a> -->
</div>
</div>
<button style="text-align: right" class="btn btn-info-outline">
<i class="fa fa-eye"></i> View Albums</button>
</div>
<!-- <button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)"> <i class="fa fa-eye"></i> {{ 'Search.Similar' | translate }}</button> -->
<br/>
</div>

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

@ -6,93 +6,36 @@
<i class="fa fa-search"></i>
</div>
</div>
<div class="form-group">
<div class="radio">
<input type="radio" id="Artist" name="Mode" checked="checked" (click)="searchMode(false)">
<label for="Artist">Artist Search</label>
<input type="radio" id="Album" name="Mode" (click)="searchMode(true)">
<label for="Album">Album Search</label>
</div>
</div>
<br />
<br />
<!-- Movie content -->
<div id="movieList">
<div *ngIf="searchApplied && artistResult?.length <= 0" class='no-search-results'>
<div *ngIf="searchApplied && artistResult?.length <= 0 && !searchAlbum" class='no-search-results'>
<i class='fa fa-music no-search-results-icon'></i><div class='no-search-results-text' [translate]="'Search.NoResults'"></div>
</div>
<div *ngIf="searchApplied && albumResult?.length <= 0 && searchAlbum" class='no-search-results'>
<i class='fa fa-music no-search-results-icon'></i><div class='no-search-results-text' [translate]="'Search.NoResults'"></div>
</div>
<div *ngFor="let result of artistResult">
<div class="row" >
<div class="myBg backdrop" [style.background-image]="result.background"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<div class="col-sm-2 small-padding">
<img *ngIf="result.poster" class="img-responsive poster" src="{{result.poster}}" alt="poster">
</div>
<div class="col-sm-8 small-padding">
<div>
<a href="" target="_blank">
<h4>{{result.artistName}}</h4>
</a>
<span class="tags">
<!-- <span *ngIf="result.releaseDate" class="label label-info" id="releaseDateLabel" target="_blank">{{ 'Search.TheatricalRelease' | translate: {date: result.releaseDate | date: 'mediumDate'} }}</span>
<span *ngIf="result.digitalReleaseDate" class="label label-info" id="releaseDateLabel" target="_blank">{{ 'Search.DigitalDate' | translate: {date: result.digitalReleaseDate | date: 'mediumDate'} }}</span>
<a *ngIf="result.homepage" href="{{result.homepage}}" id="homePageLabel" target="_blank"><span class="label label-info" [translate]="'Search.Movies.HomePage'"></span></a>
<a *ngIf="result.trailer" href="{{result.trailer}}" id="trailerLabel" target="_blank"><span class="label label-info" [translate]="'Search.Movies.Trailer'"></span></a> -->
<ng-template [ngIf]="result.available"><span class="label label-success" id="availableLabel" [translate]="'Common.Available'"></span></ng-template>
<ng-template [ngIf]="result.approved && !result.available"><span class="label label-info" id="processingRequestLabel" [translate]="'Common.ProcessingRequest'"></span></ng-template>
<ng-template [ngIf]="result.requested && !result.approved && !result.available"><span class="label label-warning" id="pendingApprovalLabel" [translate]="'Common.PendingApproval'"></span></ng-template>
<ng-template [ngIf]="!result.requested && !result.available && !result.approved"><span class="label label-danger" id="notRequestedLabel" [translate]="'Common.NotRequested'"></span></ng-template>
</span>
<br/>
</div>
<p style="font-size: 0.9rem !important">{{result.overview | truncate: 350 }}</p>
</div>
<div class="col-sm-2 small-padding">
<div class="row" *ngIf="result.requested">
<div class="col-md-2 col-md-push-10">
<!-- <a *ngIf="result.showSubscribe && !result.subscribed" style="color:white" (click)="subscribe(result)" pTooltip="Subscribe for notifications"> <i class="fa fa-rss"></i></a>
<a *ngIf="result.showSubscribe && result.subscribed" style="color:red" (click)="unSubscribe(result)" pTooltip="Unsubscribe notification"> <i class="fa fa-rss"></i></a> -->
</div>
</div>
<div *ngIf="result.available">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i> {{ 'Common.Available' | translate }}</button>
</div>
<div *ngIf="!result.available">
<div *ngIf="result.requested || result.approved; then requestedBtn else notRequestedBtn"></div>
<ng-template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i class="fa fa-check"></i> {{ 'Common.Requested' | translate }}</button>
</ng-template>
<ng-template #notRequestedBtn>
<button style="text-align: right" class="btn btn-primary-outline" (click)="request(result)">
<i *ngIf="result.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i> <i *ngIf="!result.requestProcessing && !result.processed" class="fa fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fa fa-check"></i> {{ 'Common.Request' | translate }}</button>
</ng-template>
</div>
<!-- <button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)"> <i class="fa fa-eye"></i> {{ 'Search.Similar' | translate }}</button> -->
<br/>
<div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> Report Issue
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<!-- <li *ngFor="let cat of issueCategories"><a [routerLink]="" (click)="reportIssue(cat, result)">{{cat.value}}</a></li> -->
</ul>
</div>
</div>
</div>
<artist-search [result]="result" [defaultPoster]="defaultPoster"></artist-search>
<br/>
<br/>
</div>
<div *ngFor="let result of albumResult">
<album-search [result]="result" [defaultPoster]="defaultPoster"></album-search>
<br/>
<br/>
</div>
</div>
</div>

@ -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<string> = new Subject<string>();
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;
}
});
}
}

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

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

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

@ -202,7 +202,7 @@ namespace Ombi.Controllers
/// <remarks>We use Lidarr as the Provider</remarks>
/// <returns></returns>
[HttpGet("music/album/{searchTerm}")]
public async Task<IEnumerable<AlbumLookup>> SearchAlbum(string searchTerm)
public async Task<IEnumerable<SearchAlbumViewModel>> SearchAlbum(string searchTerm)
{
return await MusicEngine.SearchAlbum(searchTerm);
}

Loading…
Cancel
Save