Improved the UI !wip

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

@ -3,6 +3,6 @@
public class Ratings public class Ratings
{ {
public int votes { get; set; } 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> GetAlbumArtist(string foreignArtistId);
Task<ArtistResult> GetArtist(int artistId); Task<ArtistResult> GetArtist(int artistId);
Task<ArtistResult> GetArtistAlbums(string foreignArtistId); Task<ArtistResult> GetArtistAlbums(string foreignArtistId);
Task<IEnumerable<AlbumLookup>> SearchAlbum(string search); Task<IEnumerable<SearchAlbumViewModel>> SearchAlbum(string search);
Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string search); Task<IEnumerable<SearchArtistViewModel>> SearchArtist(string search);
} }
} }

@ -1,492 +1,492 @@
using Ombi.Api.TheMovieDb; //using Ombi.Api.TheMovieDb;
using Ombi.Core.Models.Requests; //using Ombi.Core.Models.Requests;
using Ombi.Helpers; //using Ombi.Helpers;
using Ombi.Store.Entities; //using Ombi.Store.Entities;
using System; //using System;
using System.Collections.Generic; //using System.Collections.Generic;
using System.Globalization; //using System.Globalization;
using System.Linq; //using System.Linq;
using System.Security.Principal; //using System.Security.Principal;
using System.Threading.Tasks; //using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; //using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; //using Microsoft.Extensions.Logging;
using Ombi.Api.Lidarr; //using Ombi.Api.Lidarr;
using Ombi.Api.TheMovieDb.Models; //using Ombi.Api.TheMovieDb.Models;
using Ombi.Core.Authentication; //using Ombi.Core.Authentication;
using Ombi.Core.Engine.Interfaces; //using Ombi.Core.Engine.Interfaces;
using Ombi.Core.Models.UI; //using Ombi.Core.Models.UI;
using Ombi.Core.Rule.Interfaces; //using Ombi.Core.Rule.Interfaces;
using Ombi.Core.Settings; //using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models; //using Ombi.Settings.Settings.Models;
using Ombi.Settings.Settings.Models.External; //using Ombi.Settings.Settings.Models.External;
using Ombi.Store.Entities.Requests; //using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository; //using Ombi.Store.Repository;
namespace Ombi.Core.Engine //namespace Ombi.Core.Engine
{ //{
public class MusicRequestEngine : BaseMediaEngine // public class MusicRequestEngine : BaseMediaEngine
{ // {
public MusicRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user, // public MusicRequestEngine(IMovieDbApi movieApi, IRequestServiceMain requestService, IPrincipal user,
INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log, // INotificationHelper helper, IRuleEvaluator r, IMovieSender sender, ILogger<MovieRequestEngine> log,
OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache, // OmbiUserManager manager, IRepository<RequestLog> rl, ICacheService cache,
ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr, // ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub, ILidarrApi lidarr,
ISettingsService<LidarrSettings> lidarrSettings) // ISettingsService<LidarrSettings> lidarrSettings)
: base(user, requestService, r, manager, cache, ombiSettings, sub) // : base(user, requestService, r, manager, cache, ombiSettings, sub)
{ // {
MovieApi = movieApi; // MovieApi = movieApi;
NotificationHelper = helper; // NotificationHelper = helper;
Sender = sender; // Sender = sender;
Logger = log; // Logger = log;
_requestLog = rl; // _requestLog = rl;
_lidarrApi = lidarr; // _lidarrApi = lidarr;
_lidarrSettings = lidarrSettings; // _lidarrSettings = lidarrSettings;
} // }
private IMovieDbApi MovieApi { get; } // private IMovieDbApi MovieApi { get; }
private INotificationHelper NotificationHelper { get; } // private INotificationHelper NotificationHelper { get; }
private IMovieSender Sender { get; } // private IMovieSender Sender { get; }
private ILogger<MovieRequestEngine> Logger { get; } // private ILogger<MovieRequestEngine> Logger { get; }
private readonly IRepository<RequestLog> _requestLog; // private readonly IRepository<RequestLog> _requestLog;
private readonly ISettingsService<LidarrSettings> _lidarrSettings; // private readonly ISettingsService<LidarrSettings> _lidarrSettings;
private readonly ILidarrApi _lidarrApi; // private readonly ILidarrApi _lidarrApi;
/// <summary> // /// <summary>
/// Requests the movie. // /// Requests the movie.
/// </summary> // /// </summary>
/// <param name="model">The model.</param> // /// <param name="model">The model.</param>
/// <returns></returns> // /// <returns></returns>
public async Task<RequestEngineResult> RequestArtist(MusicArtistRequestViewModel model) // public async Task<RequestEngineResult> RequestArtist(MusicArtistRequestViewModel model)
{ // {
var s = await _lidarrSettings.GetSettingsAsync(); // var s = await _lidarrSettings.GetSettingsAsync();
var artist = await _lidarrApi.GetArtistByForignId(model.ForeignArtistId, s.ApiKey, s.FullUri); // var artist = await _lidarrApi.GetArtistByForignId(model.ForeignArtistId, s.ApiKey, s.FullUri);
if (artist == null) // if (artist == null)
{ // {
return new RequestEngineResult // return new RequestEngineResult
{ // {
Result = false, // Result = false,
Message = "There was an issue adding this Artist!", // Message = "There was an issue adding this Artist!",
ErrorMessage = "Please try again later" // ErrorMessage = "Please try again later"
}; // };
} // }
var userDetails = await GetUser(); // var userDetails = await GetUser();
var requestModel = new MovieRequests // var requestModel = new MovieRequests
{ // {
TheMovieDbId = movieInfo.Id, // TheMovieDbId = movieInfo.Id,
RequestType = RequestType.Movie, // RequestType = RequestType.Movie,
Overview = movieInfo.Overview, // Overview = movieInfo.Overview,
ImdbId = movieInfo.ImdbId, // ImdbId = movieInfo.ImdbId,
PosterPath = PosterPathHelper.FixPosterPath(movieInfo.PosterPath), // PosterPath = PosterPathHelper.FixPosterPath(movieInfo.PosterPath),
Title = movieInfo.Title, // Title = movieInfo.Title,
ReleaseDate = !string.IsNullOrEmpty(movieInfo.ReleaseDate) // ReleaseDate = !string.IsNullOrEmpty(movieInfo.ReleaseDate)
? DateTime.Parse(movieInfo.ReleaseDate) // ? DateTime.Parse(movieInfo.ReleaseDate)
: DateTime.MinValue, // : DateTime.MinValue,
Status = movieInfo.Status, // Status = movieInfo.Status,
RequestedDate = DateTime.UtcNow, // RequestedDate = DateTime.UtcNow,
Approved = false, // Approved = false,
RequestedUserId = userDetails.Id, // RequestedUserId = userDetails.Id,
Background = movieInfo.BackdropPath // Background = movieInfo.BackdropPath
}; // };
var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US"); // var usDates = movieInfo.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US");
requestModel.DigitalReleaseDate = usDates?.ReleaseDate // requestModel.DigitalReleaseDate = usDates?.ReleaseDate
?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate; // ?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate;
var ruleResults = (await RunRequestRules(requestModel)).ToList(); // var ruleResults = (await RunRequestRules(requestModel)).ToList();
if (ruleResults.Any(x => !x.Success)) // if (ruleResults.Any(x => !x.Success))
{ // {
return new RequestEngineResult // return new RequestEngineResult
{ // {
ErrorMessage = ruleResults.FirstOrDefault(x => x.Message.HasValue()).Message // ErrorMessage = ruleResults.FirstOrDefault(x => x.Message.HasValue()).Message
}; // };
} // }
if (requestModel.Approved) // The rules have auto approved this // if (requestModel.Approved) // The rules have auto approved this
{ // {
var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName); // var requestEngineResult = await AddMovieRequest(requestModel, fullMovieName);
if (requestEngineResult.Result) // if (requestEngineResult.Result)
{ // {
var result = await ApproveMovie(requestModel); // var result = await ApproveMovie(requestModel);
if (result.IsError) // if (result.IsError)
{ // {
Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); // Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message);
return new RequestEngineResult // return new RequestEngineResult
{ // {
Message = result.Message, // Message = result.Message,
ErrorMessage = result.Message, // ErrorMessage = result.Message,
Result = false // Result = false
}; // };
} // }
return requestEngineResult; // return requestEngineResult;
} // }
// If there are no providers then it's successful but movie has not been sent // // If there are no providers then it's successful but movie has not been sent
} // }
return await AddMovieRequest(requestModel, fullMovieName); // return await AddMovieRequest(requestModel, fullMovieName);
} // }
/// <summary> // /// <summary>
/// Gets the requests. // /// Gets the requests.
/// </summary> // /// </summary>
/// <param name="count">The count.</param> // /// <param name="count">The count.</param>
/// <param name="position">The position.</param> // /// <param name="position">The position.</param>
/// <param name="orderFilter">The order/filter type.</param> // /// <param name="orderFilter">The order/filter type.</param>
/// <returns></returns> // /// <returns></returns>
public async Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position, // public async Task<RequestsViewModel<MovieRequests>> GetRequests(int count, int position,
OrderFilterModel orderFilter) // OrderFilterModel orderFilter)
{ // {
var shouldHide = await HideFromOtherUsers(); // var shouldHide = await HideFromOtherUsers();
IQueryable<MovieRequests> allRequests; // IQueryable<MovieRequests> allRequests;
if (shouldHide.Hide) // if (shouldHide.Hide)
{ // {
allRequests = // allRequests =
MovieRepository.GetWithUser(shouldHide // MovieRepository.GetWithUser(shouldHide
.UserId); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); // .UserId); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
} // }
else // else
{ // {
allRequests = // allRequests =
MovieRepository // MovieRepository
.GetWithUser(); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync(); // .GetWithUser(); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
} // }
switch (orderFilter.AvailabilityFilter) // switch (orderFilter.AvailabilityFilter)
{ // {
case FilterType.None: // case FilterType.None:
break; // break;
case FilterType.Available: // case FilterType.Available:
allRequests = allRequests.Where(x => x.Available); // allRequests = allRequests.Where(x => x.Available);
break; // break;
case FilterType.NotAvailable: // case FilterType.NotAvailable:
allRequests = allRequests.Where(x => !x.Available); // allRequests = allRequests.Where(x => !x.Available);
break; // break;
default: // default:
throw new ArgumentOutOfRangeException(); // throw new ArgumentOutOfRangeException();
} // }
switch (orderFilter.StatusFilter) // switch (orderFilter.StatusFilter)
{ // {
case FilterType.None: // case FilterType.None:
break; // break;
case FilterType.Approved: // case FilterType.Approved:
allRequests = allRequests.Where(x => x.Approved); // allRequests = allRequests.Where(x => x.Approved);
break; // break;
case FilterType.Processing: // case FilterType.Processing:
allRequests = allRequests.Where(x => x.Approved && !x.Available); // allRequests = allRequests.Where(x => x.Approved && !x.Available);
break; // break;
case FilterType.PendingApproval: // case FilterType.PendingApproval:
allRequests = allRequests.Where(x => !x.Approved && !x.Available && !(x.Denied ?? false)); // allRequests = allRequests.Where(x => !x.Approved && !x.Available && !(x.Denied ?? false));
break; // break;
default: // default:
throw new ArgumentOutOfRangeException(); // throw new ArgumentOutOfRangeException();
} // }
var total = allRequests.Count(); // var total = allRequests.Count();
var requests = await (OrderMovies(allRequests, orderFilter.OrderType)).Skip(position).Take(count) // var requests = await (OrderMovies(allRequests, orderFilter.OrderType)).Skip(position).Take(count)
.ToListAsync(); // .ToListAsync();
requests.ForEach(async x => // requests.ForEach(async x =>
{ // {
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); // x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
await CheckForSubscription(shouldHide, x); // await CheckForSubscription(shouldHide, x);
}); // });
return new RequestsViewModel<MovieRequests> // return new RequestsViewModel<MovieRequests>
{ // {
Collection = requests, // Collection = requests,
Total = total // Total = total
}; // };
} // }
private IQueryable<MovieRequests> OrderMovies(IQueryable<MovieRequests> allRequests, OrderType type) // private IQueryable<MovieRequests> OrderMovies(IQueryable<MovieRequests> allRequests, OrderType type)
{ // {
switch (type) // switch (type)
{ // {
case OrderType.RequestedDateAsc: // case OrderType.RequestedDateAsc:
return allRequests.OrderBy(x => x.RequestedDate); // return allRequests.OrderBy(x => x.RequestedDate);
case OrderType.RequestedDateDesc: // case OrderType.RequestedDateDesc:
return allRequests.OrderByDescending(x => x.RequestedDate); // return allRequests.OrderByDescending(x => x.RequestedDate);
case OrderType.TitleAsc: // case OrderType.TitleAsc:
return allRequests.OrderBy(x => x.Title); // return allRequests.OrderBy(x => x.Title);
case OrderType.TitleDesc: // case OrderType.TitleDesc:
return allRequests.OrderByDescending(x => x.Title); // return allRequests.OrderByDescending(x => x.Title);
case OrderType.StatusAsc: // case OrderType.StatusAsc:
return allRequests.OrderBy(x => x.Status); // return allRequests.OrderBy(x => x.Status);
case OrderType.StatusDesc: // case OrderType.StatusDesc:
return allRequests.OrderByDescending(x => x.Status); // return allRequests.OrderByDescending(x => x.Status);
default: // default:
throw new ArgumentOutOfRangeException(nameof(type), type, null); // throw new ArgumentOutOfRangeException(nameof(type), type, null);
} // }
} // }
public async Task<int> GetTotal() // public async Task<int> GetTotal()
{ // {
var shouldHide = await HideFromOtherUsers(); // var shouldHide = await HideFromOtherUsers();
if (shouldHide.Hide) // if (shouldHide.Hide)
{ // {
return await MovieRepository.GetWithUser(shouldHide.UserId).CountAsync(); // return await MovieRepository.GetWithUser(shouldHide.UserId).CountAsync();
} // }
else // else
{ // {
return await MovieRepository.GetWithUser().CountAsync(); // return await MovieRepository.GetWithUser().CountAsync();
} // }
} // }
/// <summary> // /// <summary>
/// Gets the requests. // /// Gets the requests.
/// </summary> // /// </summary>
/// <returns></returns> // /// <returns></returns>
public async Task<IEnumerable<MovieRequests>> GetRequests() // public async Task<IEnumerable<MovieRequests>> GetRequests()
{ // {
var shouldHide = await HideFromOtherUsers(); // var shouldHide = await HideFromOtherUsers();
List<MovieRequests> allRequests; // List<MovieRequests> allRequests;
if (shouldHide.Hide) // if (shouldHide.Hide)
{ // {
allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync(); // allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync();
} // }
else // else
{ // {
allRequests = await MovieRepository.GetWithUser().ToListAsync(); // allRequests = await MovieRepository.GetWithUser().ToListAsync();
} // }
allRequests.ForEach(async x => // allRequests.ForEach(async x =>
{ // {
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); // x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
await CheckForSubscription(shouldHide, x); // await CheckForSubscription(shouldHide, x);
}); // });
return allRequests; // return allRequests;
} // }
private async Task CheckForSubscription(HideResult shouldHide, MovieRequests x) // private async Task CheckForSubscription(HideResult shouldHide, MovieRequests x)
{ // {
if (shouldHide.UserId == x.RequestedUserId) // if (shouldHide.UserId == x.RequestedUserId)
{ // {
x.ShowSubscribe = false; // x.ShowSubscribe = false;
} // }
else // else
{ // {
x.ShowSubscribe = true; // x.ShowSubscribe = true;
var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s => // var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s =>
s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.Movie); // s.UserId == shouldHide.UserId && s.RequestId == x.Id && s.RequestType == RequestType.Movie);
x.Subscribed = sub != null; // x.Subscribed = sub != null;
} // }
} // }
/// <summary> // /// <summary>
/// Searches the movie request. // /// Searches the movie request.
/// </summary> // /// </summary>
/// <param name="search">The search.</param> // /// <param name="search">The search.</param>
/// <returns></returns> // /// <returns></returns>
public async Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search) // public async Task<IEnumerable<MovieRequests>> SearchMovieRequest(string search)
{ // {
var shouldHide = await HideFromOtherUsers(); // var shouldHide = await HideFromOtherUsers();
List<MovieRequests> allRequests; // List<MovieRequests> allRequests;
if (shouldHide.Hide) // if (shouldHide.Hide)
{ // {
allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync(); // allRequests = await MovieRepository.GetWithUser(shouldHide.UserId).ToListAsync();
} // }
else // else
{ // {
allRequests = await MovieRepository.GetWithUser().ToListAsync(); // allRequests = await MovieRepository.GetWithUser().ToListAsync();
} // }
var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList(); // var results = allRequests.Where(x => x.Title.Contains(search, CompareOptions.IgnoreCase)).ToList();
results.ForEach(async x => // results.ForEach(async x =>
{ // {
x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath); // x.PosterPath = PosterPathHelper.FixPosterPath(x.PosterPath);
await CheckForSubscription(shouldHide, x); // await CheckForSubscription(shouldHide, x);
}); // });
return results; // return results;
} // }
public async Task<RequestEngineResult> ApproveMovieById(int requestId) // public async Task<RequestEngineResult> ApproveMovieById(int requestId)
{ // {
var request = await MovieRepository.Find(requestId); // var request = await MovieRepository.Find(requestId);
return await ApproveMovie(request); // return await ApproveMovie(request);
} // }
public async Task<RequestEngineResult> DenyMovieById(int modelId) // public async Task<RequestEngineResult> DenyMovieById(int modelId)
{ // {
var request = await MovieRepository.Find(modelId); // var request = await MovieRepository.Find(modelId);
if (request == null) // if (request == null)
{ // {
return new RequestEngineResult // return new RequestEngineResult
{ // {
ErrorMessage = "Request does not exist" // ErrorMessage = "Request does not exist"
}; // };
} // }
request.Denied = true; // request.Denied = true;
// We are denying a request // // We are denying a request
NotificationHelper.Notify(request, NotificationType.RequestDeclined); // NotificationHelper.Notify(request, NotificationType.RequestDeclined);
await MovieRepository.Update(request); // await MovieRepository.Update(request);
return new RequestEngineResult // return new RequestEngineResult
{ // {
Message = "Request successfully deleted", // Message = "Request successfully deleted",
}; // };
} // }
public async Task<RequestEngineResult> ApproveMovie(MovieRequests request) // public async Task<RequestEngineResult> ApproveMovie(MovieRequests request)
{ // {
if (request == null) // if (request == null)
{ // {
return new RequestEngineResult // return new RequestEngineResult
{ // {
ErrorMessage = "Request does not exist" // ErrorMessage = "Request does not exist"
}; // };
} // }
request.Approved = true; // request.Approved = true;
request.Denied = false; // request.Denied = false;
await MovieRepository.Update(request); // await MovieRepository.Update(request);
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification); // var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification);
if (canNotify.Success) // if (canNotify.Success)
{ // {
NotificationHelper.Notify(request, NotificationType.RequestApproved); // NotificationHelper.Notify(request, NotificationType.RequestApproved);
} // }
if (request.Approved) // if (request.Approved)
{ // {
var result = await Sender.Send(request); // var result = await Sender.Send(request);
if (result.Success && result.Sent) // if (result.Success && result.Sent)
{ // {
return new RequestEngineResult // return new RequestEngineResult
{ // {
Result = true // Result = true
}; // };
} // }
if (!result.Success) // if (!result.Success)
{ // {
Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message); // Logger.LogWarning("Tried auto sending movie but failed. Message: {0}", result.Message);
return new RequestEngineResult // return new RequestEngineResult
{ // {
Message = result.Message, // Message = result.Message,
ErrorMessage = result.Message, // ErrorMessage = result.Message,
Result = false // Result = false
}; // };
} // }
// If there are no providers then it's successful but movie has not been sent // // If there are no providers then it's successful but movie has not been sent
} // }
return new RequestEngineResult // return new RequestEngineResult
{ // {
Result = true // Result = true
}; // };
} // }
/// <summary> // /// <summary>
/// Updates the movie request. // /// Updates the movie request.
/// </summary> // /// </summary>
/// <param name="request">The request.</param> // /// <param name="request">The request.</param>
/// <returns></returns> // /// <returns></returns>
public async Task<MovieRequests> UpdateMovieRequest(MovieRequests request) // public async Task<MovieRequests> UpdateMovieRequest(MovieRequests request)
{ // {
var allRequests = await MovieRepository.GetWithUser().ToListAsync(); // var allRequests = await MovieRepository.GetWithUser().ToListAsync();
var results = allRequests.FirstOrDefault(x => x.Id == request.Id); // var results = allRequests.FirstOrDefault(x => x.Id == request.Id);
results.Approved = request.Approved; // results.Approved = request.Approved;
results.Available = request.Available; // results.Available = request.Available;
results.Denied = request.Denied; // results.Denied = request.Denied;
results.DeniedReason = request.DeniedReason; // results.DeniedReason = request.DeniedReason;
results.ImdbId = request.ImdbId; // results.ImdbId = request.ImdbId;
results.IssueId = request.IssueId; // results.IssueId = request.IssueId;
results.Issues = request.Issues; // results.Issues = request.Issues;
results.Overview = request.Overview; // results.Overview = request.Overview;
results.PosterPath = PosterPathHelper.FixPosterPath(request.PosterPath); // results.PosterPath = PosterPathHelper.FixPosterPath(request.PosterPath);
results.QualityOverride = request.QualityOverride; // results.QualityOverride = request.QualityOverride;
results.RootPathOverride = request.RootPathOverride; // results.RootPathOverride = request.RootPathOverride;
await MovieRepository.Update(results); // await MovieRepository.Update(results);
return results; // return results;
} // }
/// <summary> // /// <summary>
/// Removes the movie request. // /// Removes the movie request.
/// </summary> // /// </summary>
/// <param name="requestId">The request identifier.</param> // /// <param name="requestId">The request identifier.</param>
/// <returns></returns> // /// <returns></returns>
public async Task RemoveMovieRequest(int requestId) // public async Task RemoveMovieRequest(int requestId)
{ // {
var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId); // var request = await MovieRepository.GetAll().FirstOrDefaultAsync(x => x.Id == requestId);
await MovieRepository.Delete(request); // await MovieRepository.Delete(request);
} // }
public async Task<bool> UserHasRequest(string userId) // public async Task<bool> UserHasRequest(string userId)
{ // {
return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId); // return await MovieRepository.GetAll().AnyAsync(x => x.RequestedUserId == userId);
} // }
public async Task<RequestEngineResult> MarkUnavailable(int modelId) // public async Task<RequestEngineResult> MarkUnavailable(int modelId)
{ // {
var request = await MovieRepository.Find(modelId); // var request = await MovieRepository.Find(modelId);
if (request == null) // if (request == null)
{ // {
return new RequestEngineResult // return new RequestEngineResult
{ // {
ErrorMessage = "Request does not exist" // ErrorMessage = "Request does not exist"
}; // };
} // }
request.Available = false; // request.Available = false;
await MovieRepository.Update(request); // await MovieRepository.Update(request);
return new RequestEngineResult // return new RequestEngineResult
{ // {
Message = "Request is now unavailable", // Message = "Request is now unavailable",
Result = true // Result = true
}; // };
} // }
public async Task<RequestEngineResult> MarkAvailable(int modelId) // public async Task<RequestEngineResult> MarkAvailable(int modelId)
{ // {
var request = await MovieRepository.Find(modelId); // var request = await MovieRepository.Find(modelId);
if (request == null) // if (request == null)
{ // {
return new RequestEngineResult // return new RequestEngineResult
{ // {
ErrorMessage = "Request does not exist" // ErrorMessage = "Request does not exist"
}; // };
} // }
request.Available = true; // request.Available = true;
request.MarkedAsAvailable = DateTime.Now; // request.MarkedAsAvailable = DateTime.Now;
NotificationHelper.Notify(request, NotificationType.RequestAvailable); // NotificationHelper.Notify(request, NotificationType.RequestAvailable);
await MovieRepository.Update(request); // await MovieRepository.Update(request);
return new RequestEngineResult // return new RequestEngineResult
{ // {
Message = "Request is now available", // Message = "Request is now available",
Result = true // Result = true
}; // };
} // }
private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string movieName) // private async Task<RequestEngineResult> AddMovieRequest(MovieRequests model, string movieName)
{ // {
await MovieRepository.Add(model); // await MovieRepository.Add(model);
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification); // var result = await RunSpecificRule(model, SpecificRules.CanSendNotification);
if (result.Success) // if (result.Success)
{ // {
NotificationHelper.NewRequest(model); // NotificationHelper.NewRequest(model);
} // }
await _requestLog.Add(new RequestLog // await _requestLog.Add(new RequestLog
{ // {
UserId = (await GetUser()).Id, // UserId = (await GetUser()).Id,
RequestDate = DateTime.UtcNow, // RequestDate = DateTime.UtcNow,
RequestId = model.Id, // RequestId = model.Id,
RequestType = RequestType.Movie, // RequestType = RequestType.Movie,
}); // });
return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!"}; // return new RequestEngineResult {Result = true, Message = $"{movieName} has been successfully added!"};
} // }
} // }
} //}

@ -47,12 +47,17 @@ namespace Ombi.Core.Engine
/// </summary> /// </summary>
/// <param name="search">The search.</param> /// <param name="search">The search.</param>
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<AlbumLookup>> SearchAlbum(string search) public async Task<IEnumerable<SearchAlbumViewModel>> SearchAlbum(string search)
{ {
var settings = await GetSettings(); var settings = await GetSettings();
var result = await _lidarrApi.AlbumLookup(search, settings.ApiKey, settings.FullUri); 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> /// <summary>
@ -74,30 +79,6 @@ namespace Ombi.Core.Engine
return vm; 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> /// <summary>
/// Returns all albums by the specified artist /// Returns all albums by the specified artist
/// </summary> /// </summary>
@ -126,7 +107,62 @@ namespace Ombi.Core.Engine
return await _lidarrApi.GetArtist(artistId, settings.ApiKey, settings.FullUri); 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 LidarrSettings _settings;
private async Task<LidarrSettings> GetSettings() 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 { export interface ISearchArtistResult {
artistName: string; artistName: string;
artistType: string;
disambiguation: string;
forignArtistId: string; forignArtistId: string;
banner: string; banner: string;
@ -10,6 +12,7 @@
requested: boolean; requested: boolean;
requestId: number; requestId: number;
available: boolean; available: boolean;
links: ILink[];
subscribed: boolean; subscribed: boolean;
showSubscribe: boolean; showSubscribe: boolean;
@ -19,3 +22,30 @@
processed: boolean; processed: boolean;
background: any; 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> <i class="fa fa-search"></i>
</div> </div>
</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 />
<br /> <br />
<!-- Movie content -->
<div id="movieList"> <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> <i class='fa fa-music no-search-results-icon'></i><div class='no-search-results-text' [translate]="'Search.NoResults'"></div>
</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 *ngFor="let result of artistResult">
<artist-search [result]="result" [defaultPoster]="defaultPoster"></artist-search>
<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>
<br/> <br/>
<br/> <br/>
</div> </div>
<div *ngFor="let result of albumResult">
<album-search [result]="result" [defaultPoster]="defaultPoster"></album-search>
<br/>
<br/>
</div>
</div> </div>
</div> </div>

@ -7,7 +7,7 @@ import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../../auth/auth.service"; import { AuthService } from "../../auth/auth.service";
import { IIssueCategory, IRequestEngineResult, ISearchMovieResult } from "../../interfaces"; import { IIssueCategory, IRequestEngineResult, ISearchMovieResult } from "../../interfaces";
import { ISearchArtistResult } from "../../interfaces/ISearchMusicResult"; import { ISearchAlbumResult, ISearchArtistResult } from "../../interfaces/ISearchMusicResult";
import { NotificationService, RequestService, SearchService } from "../../services"; import { NotificationService, RequestService, SearchService } from "../../services";
@Component({ @Component({
@ -19,6 +19,7 @@ export class MusicSearchComponent implements OnInit {
public searchText: string; public searchText: string;
public searchChanged: Subject<string> = new Subject<string>(); public searchChanged: Subject<string> = new Subject<string>();
public artistResult: ISearchArtistResult[]; public artistResult: ISearchArtistResult[];
public albumResult: ISearchAlbumResult[];
public result: IRequestEngineResult; public result: IRequestEngineResult;
public searchApplied = false; public searchApplied = false;
public searchAlbum: boolean; public searchAlbum: boolean;
@ -35,9 +36,8 @@ export class MusicSearchComponent implements OnInit {
constructor( constructor(
private searchService: SearchService, private requestService: RequestService, private searchService: SearchService, private requestService: RequestService,
private notificationService: NotificationService, private authService: AuthService, private notificationService: NotificationService, private authService: AuthService,
private readonly translate: TranslateService, private readonly translate: TranslateService, private sanitizer: DomSanitizer,
private readonly platformLocation: PlatformLocation, private readonly platformLocation: PlatformLocation) {
private sanitizer: DomSanitizer) {
this.searchChanged.pipe( this.searchChanged.pipe(
debounceTime(600), // Wait Xms after the last event before emitting last event debounceTime(600), // Wait Xms after the last event before emitting last event
@ -45,22 +45,27 @@ export class MusicSearchComponent implements OnInit {
).subscribe(x => { ).subscribe(x => {
this.searchText = x as string; this.searchText = x as string;
if (this.searchText === "") { if (this.searchText === "") {
this.clearResults(); if(this.searchAlbum) {
this.clearAlbumResults();
} else {
this.clearArtistResults();
}
return; return;
} }
if(this.searchAlbum) { if(this.searchAlbum) {
this.searchService.searchAlbum(this.searchText) this.searchService.searchAlbum(this.searchText)
.subscribe(x => { .subscribe(x => {
this.artistResult = x; this.albumResult = x;
this.searchApplied = true; this.searchApplied = true;
this.setBackground(); this.setAlbumBackground();
}); });
} else { } else {
this.searchService.searchArtist(this.searchText) this.searchService.searchArtist(this.searchText)
.subscribe(x => { .subscribe(x => {
this.artistResult = x; this.artistResult = x;
this.searchApplied = true; this.searchApplied = true;
this.setBackground(); this.setArtistBackground();
}); });
} }
}); });
@ -85,6 +90,16 @@ export class MusicSearchComponent implements OnInit {
this.searchChanged.next(text.target.value); 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) { public request(searchResult: ISearchMovieResult) {
searchResult.requested = true; searchResult.requested = true;
searchResult.requestProcessing = true; searchResult.requestProcessing = true;
@ -124,18 +139,31 @@ export class MusicSearchComponent implements OnInit {
} }
} }
private clearResults() { private clearArtistResults() {
this.artistResult = []; this.artistResult = [];
this.searchApplied = false; this.searchApplied = false;
} }
private setBackground() { private clearAlbumResults() {
this.albumResult = [];
this.searchApplied = false;
}
private setArtistBackground() {
this.artistResult.forEach((val, index) => { this.artistResult.forEach((val, index) => {
if (val.poster === null) { if (val.poster === null) {
val.poster = this.defaultPoster; val.poster = this.defaultPoster;
} }
val.background = this.sanitizer.bypassSecurityTrustStyle val.background = this.sanitizer.bypassSecurityTrustStyle
("url(" + val.banner + ")"); ("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 { MovieSearchComponent } from "./moviesearch.component";
import { MovieSearchGridComponent } from "./moviesearchgrid.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 { MusicSearchComponent } from "./music/musicsearch.component";
import { SearchComponent } from "./search.component"; import { SearchComponent } from "./search.component";
import { SeriesInformationComponent } from "./seriesinformation.component"; import { SeriesInformationComponent } from "./seriesinformation.component";
@ -43,6 +45,8 @@ const routes: Routes = [
SeriesInformationComponent, SeriesInformationComponent,
MovieSearchGridComponent, MovieSearchGridComponent,
MusicSearchComponent, MusicSearchComponent,
ArtistSearchComponent,
AlbumSearchComponent,
], ],
exports: [ exports: [
RouterModule, RouterModule,

@ -6,7 +6,7 @@ import { TruncateModule } from "@yellowspot/ng-truncate";
import { IssuesReportComponent } from "./issues-report.component"; import { IssuesReportComponent } from "./issues-report.component";
import { SidebarModule } from "primeng/primeng"; import { InputSwitchModule, SidebarModule } from "primeng/primeng";
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -16,6 +16,7 @@ import { SidebarModule } from "primeng/primeng";
SidebarModule, SidebarModule,
FormsModule, FormsModule,
CommonModule, CommonModule,
InputSwitchModule,
TruncateModule, TruncateModule,
], ],
exports: [ exports: [
@ -25,6 +26,7 @@ import { SidebarModule } from "primeng/primeng";
SidebarModule, SidebarModule,
IssuesReportComponent, IssuesReportComponent,
TruncateModule, TruncateModule,
InputSwitchModule,
], ],
}) })
export class SharedModule {} export class SharedModule {}

@ -990,4 +990,17 @@ a > h4:hover {
.modal-footer .btn+.btn { .modal-footer .btn+.btn {
margin-left: 5px; margin-left: 5px;
margin-bottom: 10px; 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> /// <remarks>We use Lidarr as the Provider</remarks>
/// <returns></returns> /// <returns></returns>
[HttpGet("music/album/{searchTerm}")] [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); return await MusicEngine.SearchAlbum(searchTerm);
} }

Loading…
Cancel
Save