mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-19 21:03:17 -07:00
commit
91fc48c7d8
71 changed files with 6444 additions and 663 deletions
|
@ -9,6 +9,7 @@ namespace Ombi.Api.Lidarr
|
|||
{
|
||||
Task<List<AlbumLookup>> AlbumLookup(string searchTerm, string apiKey, string baseUrl);
|
||||
Task<List<ArtistLookup>> ArtistLookup(string searchTerm, string apiKey, string baseUrl);
|
||||
Task<List<Search>> Search(string searchTerm, string apiKey, string baseUrl);
|
||||
Task<List<LidarrProfile>> GetProfiles(string apiKey, string baseUrl);
|
||||
Task<List<LidarrRootFolder>> GetRootFolders(string apiKey, string baseUrl);
|
||||
Task<ArtistResult> GetArtist(int artistId, string apiKey, string baseUrl);
|
||||
|
|
|
@ -36,6 +36,15 @@ namespace Ombi.Api.Lidarr
|
|||
return _api.Request<List<LidarrRootFolder>>(request);
|
||||
}
|
||||
|
||||
public async Task<List<Search>> Search(string searchTerm, string apiKey, string baseUrl)
|
||||
{
|
||||
var request = new Request($"{ApiVersion}/search", baseUrl, HttpMethod.Get);
|
||||
request.AddQueryString("term", searchTerm);
|
||||
|
||||
AddHeaders(request, apiKey);
|
||||
return await _api.Request<List<Search>>(request);
|
||||
}
|
||||
|
||||
public async Task<List<ArtistLookup>> ArtistLookup(string searchTerm, string apiKey, string baseUrl)
|
||||
{
|
||||
var request = new Request($"{ApiVersion}/Artist/lookup", baseUrl, HttpMethod.Get);
|
||||
|
@ -83,7 +92,7 @@ namespace Ombi.Api.Lidarr
|
|||
|
||||
public Task<AlbumByArtistResponse> GetAlbumsByArtist(string foreignArtistId)
|
||||
{
|
||||
var request = new Request(string.Empty, $"https://api.lidarr.audio/api/v0.4/artist/{foreignArtistId}",
|
||||
var request = new Request(string.Empty, $"https://api.lidarr.audio/api/v1/artist/{foreignArtistId}",
|
||||
HttpMethod.Get) {IgnoreBaseUrlAppend = true};
|
||||
return _api.Request<AlbumByArtistResponse>(request);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ namespace Ombi.Api.Lidarr.Models
|
|||
public string title { get; set; }
|
||||
public string status { get; set; }
|
||||
public string artistType { get; set; }
|
||||
public string overview { get; set; }
|
||||
public string disambiguation { get; set; }
|
||||
public List<LidarrLinks> links { get; set; }
|
||||
public int artistId { get; set; }
|
||||
|
|
|
@ -32,21 +32,9 @@ namespace Ombi.Api.Lidarr.Models
|
|||
|
||||
public class Addoptions
|
||||
{
|
||||
public MonitorTypes monitor { get; set; }
|
||||
public string monitor { get; set; }
|
||||
public bool monitored { get; set; }
|
||||
public bool searchForMissingAlbums { get; set; } // Only for Artists add
|
||||
public string[] AlbumsToMonitor { get; set; } // Uses the MusicBrainzAlbumId!
|
||||
}
|
||||
|
||||
public enum MonitorTypes
|
||||
{
|
||||
All,
|
||||
Future,
|
||||
Missing,
|
||||
Existing,
|
||||
Latest,
|
||||
First,
|
||||
None,
|
||||
Unknown
|
||||
}
|
||||
}
|
13
src/Ombi.Api.Lidarr/Models/Search.cs
Normal file
13
src/Ombi.Api.Lidarr/Models/Search.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Net.Mime;
|
||||
|
||||
namespace Ombi.Api.Lidarr.Models
|
||||
{
|
||||
public class Search
|
||||
{
|
||||
public ArtistLookup artist { get; set; }
|
||||
public AlbumLookup album { get; set; }
|
||||
public string foreignId { get; set; }
|
||||
public string id { get; set; }
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Polly" Version="7.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -5,12 +5,10 @@ using System.Threading.Tasks;
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using AutoFixture;
|
||||
using Hqub.MusicBrainz.API.Entities;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Api.Lidarr.Models;
|
||||
using Ombi.Api.MusicBrainz;
|
||||
using Ombi.Core.Engine.V2;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search.V2.Music;
|
||||
|
@ -22,7 +20,6 @@ using Ombi.Settings.Settings.Models.External;
|
|||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Ombi.Test.Common;
|
||||
using Artist = Hqub.MusicBrainz.API.Entities.Artist;
|
||||
|
||||
namespace Ombi.Core.Tests.Engine.V2
|
||||
{
|
||||
|
@ -32,7 +29,6 @@ namespace Ombi.Core.Tests.Engine.V2
|
|||
|
||||
private MusicSearchEngineV2 _engine;
|
||||
|
||||
private Mock<IMusicBrainzApi> _musicApi;
|
||||
private Mock<ILidarrApi> _lidarrApi;
|
||||
private Mock<ISettingsService<LidarrSettings>> _lidarrSettings;
|
||||
private Fixture F;
|
||||
|
@ -52,118 +48,14 @@ namespace Ombi.Core.Tests.Engine.V2
|
|||
var cache = new Mock<ICacheService>();
|
||||
var ombiSettings = new Mock<ISettingsService<OmbiSettings>>();
|
||||
var requestSub = new Mock<IRepository<RequestSubscription>>();
|
||||
_musicApi = new Mock<IMusicBrainzApi>();
|
||||
_lidarrSettings = new Mock<ISettingsService<LidarrSettings>>();
|
||||
_lidarrApi = new Mock<ILidarrApi>();
|
||||
_lidarrSettings.Setup(x => x.GetSettingsAsync()).ReturnsAsync(new LidarrSettings());
|
||||
_engine = new MusicSearchEngineV2(principle.Object, requestService.Object, ruleEval.Object,
|
||||
um.Object, cache.Object, ombiSettings.Object, requestSub.Object, _musicApi.Object,
|
||||
um.Object, cache.Object, ombiSettings.Object, requestSub.Object,
|
||||
_lidarrSettings.Object, _lidarrApi.Object);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task GetBasicArtistInformation_SingleArtist_Test()
|
||||
{
|
||||
_musicApi.Setup(x => x.GetArtistInformation("pretend-artist-id")).ReturnsAsync(F.Create<Artist>());
|
||||
|
||||
var result = await _engine.GetArtistInformation("pretend-artist-id");
|
||||
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.ReleaseGroups.Any(), Is.True, "Release Groups are null");
|
||||
Assert.That(result.Members.Any(), Is.False, "Members somehow populated?");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetBasicArtistInformation_Group_Test()
|
||||
{
|
||||
var musicReturnVal = F.Build<Artist>().With(x => x.Relations, new List<Relation>
|
||||
{
|
||||
new Relation
|
||||
{
|
||||
TypeId = RelationLinks.BandMember,
|
||||
Artist = new Artist
|
||||
{
|
||||
Name = "Mr Artist"
|
||||
},
|
||||
Attributes = new []{"a nobody"},
|
||||
Begin = "1992",
|
||||
End = "2019",
|
||||
Ended = true
|
||||
},
|
||||
new Relation
|
||||
{
|
||||
TypeId = RelationLinks.BandMember,
|
||||
Artist = new Artist
|
||||
{
|
||||
Name = "Mr Artist2"
|
||||
},
|
||||
Attributes = new []{"a nobody2"},
|
||||
Begin = "1993",
|
||||
}
|
||||
});
|
||||
_musicApi.Setup(x => x.GetArtistInformation("pretend-artist-id")).ReturnsAsync(musicReturnVal.Create());
|
||||
|
||||
var result = await _engine.GetArtistInformation("pretend-artist-id");
|
||||
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.ReleaseGroups.Any(), Is.True, "Release Groups are null");
|
||||
Assert.That(result.Members.Any(), Is.True, "Members IS NULL!");
|
||||
|
||||
Assert.That(result.Members.FirstOrDefault(x => x.Name == "Mr Artist").End, Is.EqualTo("2019"));
|
||||
Assert.That(result.Members.FirstOrDefault(x => x.Name == "Mr Artist").Attributes.Length, Is.EqualTo(1));
|
||||
Assert.That(result.Members.FirstOrDefault(x => x.Name == "Mr Artist").IsCurrentMember, Is.EqualTo(false));
|
||||
Assert.That(result.Members.FirstOrDefault(x => x.Name == "Mr Artist").Start, Is.EqualTo("1992"));
|
||||
|
||||
Assert.That(result.Members.FirstOrDefault(x => x.Name == "Mr Artist2").IsCurrentMember, Is.EqualTo(true));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(LinksData))]
|
||||
public async Task<string> GetBasicArtistInformation_Links_Test(string url, string typeId, Func<ArtistInformation, string> func)
|
||||
{
|
||||
var musicReturnVal = F.Build<Artist>().With(x => x.Relations, new List<Relation>
|
||||
{
|
||||
new Relation
|
||||
{
|
||||
TypeId = typeId,
|
||||
Url = new Url
|
||||
{
|
||||
Resource = url
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
_musicApi.Setup(x => x.GetArtistInformation("pretend-artist-id")).ReturnsAsync(musicReturnVal.Create());
|
||||
|
||||
var result = await _engine.GetArtistInformation("pretend-artist-id");
|
||||
|
||||
Assert.That(result, Is.Not.Null);
|
||||
return func(result);
|
||||
}
|
||||
|
||||
private static IEnumerable<TestCaseData> LinksData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new TestCaseData("twitter.com", RelationLinks.SocialNetwork, new Func<ArtistInformation, string>(artist => artist.Links.Twitter)).Returns("twitter.com").SetName("ArtistInformation_Links_Twitter");
|
||||
yield return new TestCaseData("allmusic", RelationLinks.AllMusic, new Func<ArtistInformation, string>(artist => artist.Links.AllMusic)).Returns("allmusic").SetName("ArtistInformation_Links_AllMusic");
|
||||
yield return new TestCaseData("bbcmusic", RelationLinks.BbcMusic, new Func<ArtistInformation, string>(artist => artist.Links.BbcMusic)).Returns("bbcmusic").SetName("ArtistInformation_Links_BbcMusic");
|
||||
yield return new TestCaseData("discogs", RelationLinks.Discogs, new Func<ArtistInformation, string>(artist => artist.Links.Discogs)).Returns("discogs").SetName("ArtistInformation_Links_Discogs");
|
||||
yield return new TestCaseData("homepage", RelationLinks.Homepage, new Func<ArtistInformation, string>(artist => artist.Links.HomePage)).Returns("homepage").SetName("ArtistInformation_Links_Homepage");
|
||||
yield return new TestCaseData("imdb", RelationLinks.Imdb, new Func<ArtistInformation, string>(artist => artist.Links.Imdb)).Returns("imdb").SetName("ArtistInformation_Links_Imdb");
|
||||
yield return new TestCaseData("lastfm", RelationLinks.LastFm, new Func<ArtistInformation, string>(artist => artist.Links.LastFm)).Returns("lastfm").SetName("ArtistInformation_Links_LastFm");
|
||||
yield return new TestCaseData("myspace", RelationLinks.MySpace, new Func<ArtistInformation, string>(artist => artist.Links.MySpace)).Returns("myspace").SetName("ArtistInformation_Links_MySpace");
|
||||
yield return new TestCaseData("onlinecommunity", RelationLinks.OnlineCommunity, new Func<ArtistInformation, string>(artist => artist.Links.OnlineCommunity)).Returns("onlinecommunity").SetName("ArtistInformation_Links_OnlineCommunity");
|
||||
yield return new TestCaseData("www.facebook.com", RelationLinks.SocialNetwork, new Func<ArtistInformation, string>(artist => artist.Links.Facebook)).Returns("www.facebook.com").SetName("ArtistInformation_Links_Facebook");
|
||||
yield return new TestCaseData("www.instagram.com", RelationLinks.SocialNetwork, new Func<ArtistInformation, string>(artist => artist.Links.Instagram)).Returns("www.instagram.com").SetName("ArtistInformation_Links_insta");
|
||||
yield return new TestCaseData("www.vk.com", RelationLinks.SocialNetwork, new Func<ArtistInformation, string>(artist => artist.Links.Vk)).Returns("www.vk.com").SetName("ArtistInformation_Links_vk");
|
||||
yield return new TestCaseData("app.spotify.com", RelationLinks.Streams, new Func<ArtistInformation, string>(artist => artist.Links.Spotify)).Returns("app.spotify.com").SetName("ArtistInformation_Links_Spotify");
|
||||
yield return new TestCaseData("deezer.com", RelationLinks.Streams, new Func<ArtistInformation, string>(artist => artist.Links.Deezer)).Returns("deezer.com").SetName("ArtistInformation_Links_Deezer");
|
||||
yield return new TestCaseData("play.google.com", RelationLinks.Download, new Func<ArtistInformation, string>(artist => artist.Links.Google)).Returns("play.google.com").SetName("ArtistInformation_Links_Google");
|
||||
yield return new TestCaseData("itunes.apple.com", RelationLinks.Download, new Func<ArtistInformation, string>(artist => artist.Links.Apple)).Returns("itunes.apple.com").SetName("ArtistInformation_Links_Apple");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task GetArtistInformation_WithPosters()
|
||||
{
|
||||
|
@ -200,7 +92,6 @@ namespace Ombi.Core.Tests.Engine.V2
|
|||
},
|
||||
}
|
||||
});
|
||||
_musicApi.Setup(x => x.GetArtistInformation("pretend-artist-id")).ReturnsAsync(F.Create<Artist>());
|
||||
|
||||
var result = await _engine.GetArtistInformation("pretend-artist-id");
|
||||
|
||||
|
|
|
@ -10,20 +10,21 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
public interface IMusicRequestEngine
|
||||
{
|
||||
Task<RequestEngineResult>ApproveAlbum(AlbumRequest request);
|
||||
Task<RequestEngineResult>ApproveAlbum(MusicRequests request);
|
||||
Task<RequestEngineResult> ApproveAlbumById(int requestId);
|
||||
Task<RequestEngineResult> DenyAlbumById(int modelId, string reason);
|
||||
Task<IEnumerable<AlbumRequest>> GetRequests();
|
||||
Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, OrderFilterModel orderFilter);
|
||||
Task<IEnumerable<MusicRequests>> GetRequests();
|
||||
Task<RequestsViewModel<MusicRequests>> GetRequests(int count, int position, OrderFilterModel orderFilter);
|
||||
Task<int> GetTotal();
|
||||
Task<RequestEngineResult> MarkAvailable(int modelId);
|
||||
Task<RequestEngineResult> MarkUnavailable(int modelId);
|
||||
Task RemoveAlbumRequest(int requestId);
|
||||
Task<RequestEngineResult> RequestAlbum(MusicAlbumRequestViewModel model);
|
||||
Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search);
|
||||
Task<RequestEngineResult> RequestArtist(MusicArtistRequestViewModel model);
|
||||
Task<IEnumerable<MusicRequests>> SearchAlbumRequest(string search);
|
||||
Task<bool> UserHasRequest(string userId);
|
||||
Task<RequestQuotaCountModel> GetRemainingRequests(OmbiUser user = null);
|
||||
Task<RequestsViewModel<AlbumRequest>> GetRequestsByStatus(int count, int position, string sort, string sortOrder, RequestStatus available);
|
||||
Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, string sort, string sortOrder);
|
||||
Task<RequestsViewModel<MusicRequests>> GetRequestsByStatus(int count, int position, string sort, string sortOrder, RequestStatus available);
|
||||
Task<RequestsViewModel<MusicRequests>> GetRequests(int count, int position, string sort, string sortOrder);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,6 @@ namespace Ombi.Core.Engine.Interfaces
|
|||
Task<ArtistInformation> GetArtistInformation(string artistId);
|
||||
Task<ArtistInformation> GetArtistInformationByRequestId(int requestId);
|
||||
Task<AlbumArt> GetReleaseGroupArt(string musicBrainzId, CancellationToken token);
|
||||
Task<ReleaseGroup> GetAlbum(string albumId);
|
||||
Task<AlbumInformation> GetAlbumInformation(string albumId);
|
||||
}
|
||||
}
|
|
@ -73,7 +73,7 @@ namespace Ombi.Core.Engine
|
|||
|
||||
var userDetails = await GetUser();
|
||||
|
||||
var requestModel = new AlbumRequest
|
||||
var requestModel = new MusicRequests
|
||||
{
|
||||
ForeignAlbumId = model.ForeignAlbumId,
|
||||
ArtistName = album.artist?.artistName,
|
||||
|
@ -85,8 +85,10 @@ namespace Ombi.Core.Engine
|
|||
Title = album.title,
|
||||
Disk = album.images?.FirstOrDefault(x => x.coverType.Equals("disc"))?.url,
|
||||
Cover = album.images?.FirstOrDefault(x => x.coverType.Equals("cover"))?.url,
|
||||
ForeignArtistId = album?.artist?.foreignArtistId ?? string.Empty, // This needs to be populated to send to Lidarr for new requests
|
||||
RequestedByAlias = model.RequestedByAlias
|
||||
ForeignArtistId = album.artist?.foreignArtistId,
|
||||
RequestedByAlias = model.RequestedByAlias,
|
||||
Monitor = model.Monitor,
|
||||
SearchForMissingAlbums = model.SearchForMissingAlbums
|
||||
};
|
||||
if (requestModel.Cover.IsNullOrEmpty())
|
||||
{
|
||||
|
@ -128,6 +130,58 @@ namespace Ombi.Core.Engine
|
|||
return await AddAlbumRequest(requestModel);
|
||||
}
|
||||
|
||||
public async Task<RequestEngineResult> RequestArtist(MusicArtistRequestViewModel model)
|
||||
{
|
||||
var s = await _lidarrSettings.GetSettingsAsync();
|
||||
var artist = await _lidarrApi.GetArtistByForeignId(model.ForeignArtistId, s.ApiKey, s.FullUri);
|
||||
var userDetails = await GetUser();
|
||||
var requestModel = new MusicRequests
|
||||
{
|
||||
ForeignArtistId = model.ForeignArtistId,
|
||||
Monitored = model.Monitored,
|
||||
Title = artist.artistName,
|
||||
ArtistName = artist.artistName,
|
||||
RequestedDate = DateTime.Now,
|
||||
RequestType = RequestType.Artist,
|
||||
RequestedUserId = userDetails.Id,
|
||||
Monitor = model.Monitor,
|
||||
SearchForMissingAlbums = model.SearchForMissingAlbums
|
||||
};
|
||||
|
||||
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 AddArtistRequest(requestModel);
|
||||
if (requestEngineResult.Result)
|
||||
{
|
||||
var result = await ApproveArtist(requestModel);
|
||||
if (result.IsError)
|
||||
{
|
||||
Logger.LogWarning("Tried auto sending Album 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 album has not been sent
|
||||
}
|
||||
|
||||
return await AddArtistRequest(requestModel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the requests.
|
||||
/// </summary>
|
||||
|
@ -135,11 +189,11 @@ namespace Ombi.Core.Engine
|
|||
/// <param name="position">The position.</param>
|
||||
/// <param name="orderFilter">The order/filter type.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position,
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetRequests(int count, int position,
|
||||
OrderFilterModel orderFilter)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
IQueryable<AlbumRequest> allRequests;
|
||||
IQueryable<MusicRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests =
|
||||
|
@ -193,14 +247,86 @@ namespace Ombi.Core.Engine
|
|||
{
|
||||
await CheckForSubscription(shouldHide, x);
|
||||
});
|
||||
return new RequestsViewModel<AlbumRequest>
|
||||
return new RequestsViewModel<MusicRequests>
|
||||
{
|
||||
Collection = requests,
|
||||
Total = total
|
||||
};
|
||||
}
|
||||
|
||||
private IQueryable<AlbumRequest> OrderAlbums(IQueryable<AlbumRequest> allRequests, OrderType type)
|
||||
/// <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<MusicRequests>> GetRequestArtist(int count, int position,
|
||||
OrderFilterModel orderFilter)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
IQueryable<MusicRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests =
|
||||
MusicRepository.GetWithUser(shouldHide
|
||||
.UserId); //.Skip(position).Take(count).OrderByDescending(x => x.ReleaseDate).ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
allRequests =
|
||||
MusicRepository
|
||||
.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 (OrderAlbums(allRequests, orderFilter.OrderType)).Skip(position).Take(count)
|
||||
.ToListAsync();
|
||||
|
||||
requests.ForEach(async x =>
|
||||
{
|
||||
await CheckForSubscription(shouldHide, x);
|
||||
});
|
||||
return new RequestsViewModel<MusicRequests>
|
||||
{
|
||||
Collection = requests,
|
||||
Total = total
|
||||
};
|
||||
}
|
||||
|
||||
private IQueryable<MusicRequests> OrderAlbums(IQueryable<MusicRequests> allRequests, OrderType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
|
@ -234,10 +360,10 @@ namespace Ombi.Core.Engine
|
|||
/// Gets the requests.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<AlbumRequest>> GetRequests()
|
||||
public async Task<IEnumerable<MusicRequests>> GetRequests()
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
List<AlbumRequest> allRequests;
|
||||
List<MusicRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests = await MusicRepository.GetWithUser(shouldHide.UserId).ToListAsync();
|
||||
|
@ -254,8 +380,28 @@ namespace Ombi.Core.Engine
|
|||
return allRequests;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<MusicRequests>> GetRequestsArtist()
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
List<MusicRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests = await MusicRepository.GetWithUser(shouldHide.UserId).ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
allRequests = await MusicRepository.GetWithUser().ToListAsync();
|
||||
}
|
||||
|
||||
allRequests.ForEach(async x =>
|
||||
{
|
||||
await CheckForArtistSubscription(shouldHide, x);
|
||||
});
|
||||
return allRequests;
|
||||
}
|
||||
|
||||
|
||||
private async Task CheckForSubscription(HideResult shouldHide, List<AlbumRequest> albumRequests)
|
||||
private async Task CheckForSubscription(HideResult shouldHide, List<MusicRequests> albumRequests)
|
||||
{
|
||||
var requestIds = albumRequests.Select(x => x.Id);
|
||||
var sub = await _subscriptionRepository.GetAll().Where(s =>
|
||||
|
@ -276,7 +422,22 @@ namespace Ombi.Core.Engine
|
|||
}
|
||||
}
|
||||
|
||||
private async Task CheckForSubscription(HideResult shouldHide, AlbumRequest x)
|
||||
private async Task CheckForArtistSubscription(HideResult shouldHide, MusicRequests artistRequest)
|
||||
{
|
||||
if (shouldHide.UserId == artistRequest.RequestedUserId)
|
||||
{
|
||||
artistRequest.ShowSubscribe = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
artistRequest.ShowSubscribe = true;
|
||||
var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s =>
|
||||
s.UserId == shouldHide.UserId && s.RequestId == artistRequest.Id && s.RequestType == RequestType.Artist);
|
||||
artistRequest.Subscribed = sub != null;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CheckForSubscription(HideResult shouldHide, MusicRequests x)
|
||||
{
|
||||
if (shouldHide.UserId == x.RequestedUserId)
|
||||
{
|
||||
|
@ -296,10 +457,10 @@ namespace Ombi.Core.Engine
|
|||
/// </summary>
|
||||
/// <param name="search">The search.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<AlbumRequest>> SearchAlbumRequest(string search)
|
||||
public async Task<IEnumerable<MusicRequests>> SearchAlbumRequest(string search)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
List<AlbumRequest> allRequests;
|
||||
List<MusicRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests = await MusicRepository.GetWithUser(shouldHide.UserId).ToListAsync();
|
||||
|
@ -346,7 +507,7 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<RequestEngineResult> ApproveAlbum(AlbumRequest request)
|
||||
public async Task<RequestEngineResult> ApproveAlbum(MusicRequests request)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
|
@ -370,7 +531,60 @@ namespace Ombi.Core.Engine
|
|||
|
||||
if (request.Approved)
|
||||
{
|
||||
var result = await _musicSender.Send(request);
|
||||
var result = await _musicSender.SendAlbum(request);
|
||||
if (result.Success && result.Sent)
|
||||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
Result = true
|
||||
};
|
||||
}
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
Logger.LogWarning("Tried auto sending album 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
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<RequestEngineResult> ApproveArtist(MusicRequests request)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
return new RequestEngineResult
|
||||
{
|
||||
ErrorMessage = "Request does not exist"
|
||||
};
|
||||
}
|
||||
|
||||
request.MarkedAsApproved = DateTime.Now;
|
||||
request.Approved = true;
|
||||
request.Denied = false;
|
||||
await MusicRepository.Update(request);
|
||||
|
||||
|
||||
var canNotify = await RunSpecificRule(request, SpecificRules.CanSendNotification, string.Empty);
|
||||
if (canNotify.Success)
|
||||
{
|
||||
await NotificationHelper.Notify(request, NotificationType.RequestApproved);
|
||||
}
|
||||
|
||||
if (request.Approved)
|
||||
{
|
||||
var result = await _musicSender.SendArtist(request);
|
||||
if (result.Success && result.Sent)
|
||||
{
|
||||
return new RequestEngineResult
|
||||
|
@ -502,7 +716,7 @@ namespace Ombi.Core.Engine
|
|||
};
|
||||
}
|
||||
|
||||
private async Task<RequestEngineResult> AddAlbumRequest(AlbumRequest model)
|
||||
private async Task<RequestEngineResult> AddAlbumRequest(MusicRequests model)
|
||||
{
|
||||
await MusicRepository.Add(model);
|
||||
|
||||
|
@ -523,10 +737,32 @@ namespace Ombi.Core.Engine
|
|||
return new RequestEngineResult { Result = true, Message = $"{model.Title} has been successfully added!", RequestId = model.Id };
|
||||
}
|
||||
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetRequestsByStatus(int count, int position, string sortProperty, string sortOrder, RequestStatus status)
|
||||
private async Task<RequestEngineResult> AddArtistRequest(MusicRequests model)
|
||||
{
|
||||
// Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(MusicRepository));
|
||||
await MusicRepository.Add(model);
|
||||
|
||||
var result = await RunSpecificRule(model, SpecificRules.CanSendNotification, string.Empty);
|
||||
if (result.Success)
|
||||
{
|
||||
await NotificationHelper.NewRequest(model);
|
||||
}
|
||||
|
||||
await _requestLog.Add(new RequestLog
|
||||
{
|
||||
UserId = (await GetUser()).Id,
|
||||
RequestDate = DateTime.UtcNow,
|
||||
RequestId = model.Id,
|
||||
RequestType = RequestType.Artist,
|
||||
});
|
||||
|
||||
return new RequestEngineResult { Result = true, Message = $"{model.Title} has been successfully added!", RequestId = model.Id };
|
||||
}
|
||||
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetRequestsByStatus(int count, int position, string sortProperty, string sortOrder, RequestStatus status)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
IQueryable<AlbumRequest> allRequests;
|
||||
IQueryable<MusicRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests =
|
||||
|
@ -558,12 +794,12 @@ namespace Ombi.Core.Engine
|
|||
break;
|
||||
}
|
||||
|
||||
var prop = TypeDescriptor.GetProperties(typeof(AlbumRequest)).Find(sortProperty, true);
|
||||
var prop = TypeDescriptor.GetProperties(typeof(MusicRequests)).Find(sortProperty, true);
|
||||
|
||||
if (sortProperty.Contains('.'))
|
||||
{
|
||||
// This is a navigation property currently not supported
|
||||
prop = TypeDescriptor.GetProperties(typeof(AlbumRequest)).Find("RequestedDate", true);
|
||||
prop = TypeDescriptor.GetProperties(typeof(MusicRequests)).Find("RequestedDate", true);
|
||||
//var properties = sortProperty.Split(new []{'.'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
//var firstProp = TypeDescriptor.GetProperties(typeof(MovieRequests)).Find(properties[0], true);
|
||||
//var propType = firstProp.PropertyType;
|
||||
|
@ -578,17 +814,17 @@ namespace Ombi.Core.Engine
|
|||
requests = requests.Skip(position).Take(count).ToList();
|
||||
|
||||
await CheckForSubscription(shouldHide, requests);
|
||||
return new RequestsViewModel<AlbumRequest>
|
||||
return new RequestsViewModel<MusicRequests>
|
||||
{
|
||||
Collection = requests,
|
||||
Total = total
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, string sortProperty, string sortOrder)
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetRequests(int count, int position, string sortProperty, string sortOrder)
|
||||
{
|
||||
var shouldHide = await HideFromOtherUsers();
|
||||
IQueryable<AlbumRequest> allRequests;
|
||||
IQueryable<MusicRequests> allRequests;
|
||||
if (shouldHide.Hide)
|
||||
{
|
||||
allRequests =
|
||||
|
@ -622,7 +858,7 @@ namespace Ombi.Core.Engine
|
|||
requests = requests.Skip(position).Take(count).ToList();
|
||||
|
||||
await CheckForSubscription(shouldHide, requests);
|
||||
return new RequestsViewModel<AlbumRequest>
|
||||
return new RequestsViewModel<MusicRequests>
|
||||
{
|
||||
Collection = requests,
|
||||
Total = total
|
||||
|
|
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Ombi.Api.MusicBrainz;
|
||||
using Ombi.Api.TheMovieDb;
|
||||
using Ombi.Api.TheMovieDb.Models;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Models.Search.V2;
|
||||
|
@ -23,17 +23,18 @@ namespace Ombi.Core.Engine.V2
|
|||
{
|
||||
public MultiSearchEngine(IPrincipal identity, IRequestServiceMain requestService, IRuleEvaluator rules,
|
||||
OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings, IRepository<RequestSubscription> sub,
|
||||
IMovieDbApi movieDbApi, ISettingsService<LidarrSettings> lidarrSettings, IMusicBrainzApi musicApi)
|
||||
IMovieDbApi movieDbApi, ISettingsService<LidarrSettings> lidarrSettings, ILidarrApi lidarrApi)
|
||||
: base(identity, requestService, rules, um, cache, ombiSettings, sub)
|
||||
{
|
||||
_movieDbApi = movieDbApi;
|
||||
_lidarrSettings = lidarrSettings;
|
||||
_musicApi = musicApi;
|
||||
_lidarrApi = lidarrApi;
|
||||
}
|
||||
|
||||
private readonly IMovieDbApi _movieDbApi;
|
||||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
private readonly IMusicBrainzApi _musicApi;
|
||||
|
||||
private readonly ILidarrApi _lidarrApi;
|
||||
|
||||
private bool _demo = DemoSingleton.Instance.Demo;
|
||||
|
||||
|
@ -43,72 +44,92 @@ namespace Ombi.Core.Engine.V2
|
|||
var lang = await DefaultLanguageCode(null);
|
||||
var model = new List<MultiSearchResult>();
|
||||
|
||||
var movieDbData = (await _movieDbApi.MultiSearch(searchTerm, lang, cancellationToken)).results;
|
||||
|
||||
var lidarrSettings = await _lidarrSettings.GetSettingsAsync();
|
||||
if (lidarrSettings.Enabled && filter.Music)
|
||||
{
|
||||
var artistResult = await _musicApi.SearchArtist(searchTerm);
|
||||
foreach (var artist in artistResult)
|
||||
var lidarSearchResult = await _lidarrApi.Search(searchTerm, lidarrSettings.ApiKey, lidarrSettings.FullUri);
|
||||
foreach (var search_result in lidarSearchResult)
|
||||
{
|
||||
model.Add(new MultiSearchResult
|
||||
if (search_result.artist != null)
|
||||
{
|
||||
MediaType = "Artist",
|
||||
Title = artist.Name,
|
||||
Id = artist.Id
|
||||
});
|
||||
model.Add(new MultiSearchResult
|
||||
{
|
||||
MediaType = "Artist",
|
||||
Title = search_result.artist.artistName,
|
||||
Id = search_result.artist.foreignArtistId,
|
||||
Poster = search_result.artist.remotePoster,
|
||||
Monitored = search_result.artist.monitored
|
||||
|
||||
});
|
||||
} else if (search_result.album != null)
|
||||
{
|
||||
model.Add(new MultiSearchResult
|
||||
{
|
||||
MediaType = "Album",
|
||||
Title = search_result.album.title,
|
||||
Id = search_result.album.foreignAlbumId,
|
||||
Poster = search_result.album.remoteCover,
|
||||
Monitored = search_result.album.monitored
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var multiSearch in movieDbData)
|
||||
if (filter.Movies || filter.TvShows)
|
||||
{
|
||||
var movieDbData = (await _movieDbApi.MultiSearch(searchTerm, lang, cancellationToken)).results;
|
||||
|
||||
if (DemoCheck(multiSearch.title) || DemoCheck(multiSearch.name))
|
||||
foreach (var multiSearch in movieDbData)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = new MultiSearchResult
|
||||
{
|
||||
MediaType = multiSearch.media_type,
|
||||
Poster = multiSearch.poster_path,
|
||||
Overview = multiSearch.overview
|
||||
};
|
||||
|
||||
if (multiSearch.media_type.Equals("movie", StringComparison.InvariantCultureIgnoreCase) && filter.Movies)
|
||||
{
|
||||
if (multiSearch.release_date.HasValue() && DateTime.TryParse(multiSearch.release_date, out var releaseDate))
|
||||
if (DemoCheck(multiSearch.title) || DemoCheck(multiSearch.name))
|
||||
{
|
||||
result.Title = $"{multiSearch.title} ({releaseDate.Year})";
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Title = multiSearch.title;
|
||||
}
|
||||
}
|
||||
|
||||
else if (multiSearch.media_type.Equals("tv", StringComparison.InvariantCultureIgnoreCase) && filter.TvShows)
|
||||
{
|
||||
if (multiSearch.release_date.HasValue() && DateTime.TryParse(multiSearch.release_date, out var releaseDate))
|
||||
var result = new MultiSearchResult
|
||||
{
|
||||
result.Title = $"{multiSearch.name} ({releaseDate.Year})";
|
||||
MediaType = multiSearch.media_type,
|
||||
Poster = multiSearch.poster_path,
|
||||
Overview = multiSearch.overview
|
||||
};
|
||||
|
||||
if (multiSearch.media_type.Equals("movie", StringComparison.InvariantCultureIgnoreCase) && filter.Movies)
|
||||
{
|
||||
if (multiSearch.release_date.HasValue() && DateTime.TryParse(multiSearch.release_date, out var releaseDate))
|
||||
{
|
||||
result.Title = $"{multiSearch.title} ({releaseDate.Year})";
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Title = multiSearch.title;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
else if (multiSearch.media_type.Equals("tv", StringComparison.InvariantCultureIgnoreCase) && filter.TvShows)
|
||||
{
|
||||
if (multiSearch.release_date.HasValue() && DateTime.TryParse(multiSearch.release_date, out var releaseDate))
|
||||
{
|
||||
result.Title = $"{multiSearch.name} ({releaseDate.Year})";
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Title = multiSearch.name;
|
||||
}
|
||||
}
|
||||
else if (multiSearch.media_type.Equals("person", StringComparison.InvariantCultureIgnoreCase) && filter.People)
|
||||
{
|
||||
result.Title = multiSearch.name;
|
||||
}
|
||||
}
|
||||
else if (multiSearch.media_type.Equals("person", StringComparison.InvariantCultureIgnoreCase) && filter.People)
|
||||
{
|
||||
result.Title = multiSearch.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Id = multiSearch.id.ToString();
|
||||
model.Add(result);
|
||||
result.Id = multiSearch.id.ToString();
|
||||
model.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
|
|
|
@ -8,7 +8,6 @@ using System.Threading.Tasks;
|
|||
using Newtonsoft.Json;
|
||||
using Ombi.Api.Lidarr;
|
||||
using Ombi.Api.Lidarr.Models;
|
||||
using Ombi.Api.MusicBrainz;
|
||||
using Ombi.Core.Authentication;
|
||||
using Ombi.Core.Engine.Interfaces;
|
||||
using Ombi.Core.Models.Requests;
|
||||
|
@ -20,98 +19,108 @@ using Ombi.Settings.Settings.Models;
|
|||
using Ombi.Settings.Settings.Models.External;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Artist = Hqub.MusicBrainz.API.Entities.Artist;
|
||||
using ReleaseGroup = Ombi.Core.Models.Search.V2.Music.ReleaseGroup;
|
||||
|
||||
namespace Ombi.Core.Engine.V2
|
||||
{
|
||||
public class MusicSearchEngineV2 : BaseMediaEngine, IMusicSearchEngineV2
|
||||
{
|
||||
private readonly IMusicBrainzApi _musicBrainzApi;
|
||||
private readonly ISettingsService<LidarrSettings> _lidarrSettings;
|
||||
private readonly ILidarrApi _lidarrApi;
|
||||
|
||||
public MusicSearchEngineV2(IPrincipal identity, IRequestServiceMain requestService, IRuleEvaluator rules,
|
||||
OmbiUserManager um, ICacheService cache, ISettingsService<OmbiSettings> ombiSettings,
|
||||
IRepository<RequestSubscription> sub, IMusicBrainzApi musicBrainzApi, ISettingsService<LidarrSettings> lidarrSettings,
|
||||
IRepository<RequestSubscription> sub, ISettingsService<LidarrSettings> lidarrSettings,
|
||||
ILidarrApi lidarrApi)
|
||||
: base(identity, requestService, rules, um, cache, ombiSettings, sub)
|
||||
{
|
||||
_musicBrainzApi = musicBrainzApi;
|
||||
_lidarrSettings = lidarrSettings;
|
||||
_lidarrApi = lidarrApi;
|
||||
}
|
||||
|
||||
public async Task<ReleaseGroup> GetAlbum(string albumId)
|
||||
{
|
||||
var g = await _musicBrainzApi.GetAlbumInformation(albumId);
|
||||
var release = new ReleaseGroup
|
||||
var lidarrSettings = await GetLidarrSettings();
|
||||
Task<AlbumLookup> lidarrAlbumTask = null;
|
||||
var release = new ReleaseGroup{};
|
||||
if (lidarrSettings.Enabled)
|
||||
{
|
||||
ReleaseType = g.ReleaseGroup.PrimaryType,
|
||||
Id = g.Id,
|
||||
Title = g.Title,
|
||||
ReleaseDate = g.ReleaseGroup.FirstReleaseDate,
|
||||
};
|
||||
lidarrAlbumTask = _lidarrApi.GetAlbumByForeignId(albumId, lidarrSettings.ApiKey, lidarrSettings.FullUri);
|
||||
var albumResult = await lidarrAlbumTask;
|
||||
release = new ReleaseGroup
|
||||
{
|
||||
ReleaseType = albumResult.artistType,
|
||||
Id = albumResult.artistId.ToString(),
|
||||
Title = albumResult.title,
|
||||
ReleaseDate = albumResult.releaseDate.ToString(),
|
||||
};
|
||||
|
||||
await RunSearchRules(release);
|
||||
await RunSearchRules(release);
|
||||
}
|
||||
|
||||
return release;
|
||||
}
|
||||
|
||||
public async Task<ArtistInformation> GetArtistInformation(string artistId)
|
||||
{
|
||||
var artist = await _musicBrainzApi.GetArtistInformation(artistId);
|
||||
var lidarrSettings = await GetLidarrSettings();
|
||||
Task<ArtistResult> lidarrArtistTask = null;
|
||||
var info = new ArtistInformation { };
|
||||
if (lidarrSettings.Enabled)
|
||||
{
|
||||
lidarrArtistTask = _lidarrApi.GetArtistByForeignId(artistId, lidarrSettings.ApiKey, lidarrSettings.FullUri);
|
||||
}
|
||||
info = new ArtistInformation { };
|
||||
|
||||
var info = new ArtistInformation
|
||||
{
|
||||
Id = artistId,
|
||||
Name = artist.Name,
|
||||
Country = artist.Country,
|
||||
Region = artist.Area?.Name,
|
||||
Type = artist.Type,
|
||||
StartYear = artist.LifeSpan?.Begin ?? "",
|
||||
EndYear = artist.LifeSpan?.End ?? "",
|
||||
Disambiguation = artist.Disambiguation,
|
||||
ReleaseGroups = new List<ReleaseGroup>(),
|
||||
Members = new List<BandMember>()
|
||||
};
|
||||
|
||||
foreach (var g in artist.ReleaseGroups)
|
||||
{
|
||||
var release = new ReleaseGroup
|
||||
if (lidarrArtistTask != null)
|
||||
{
|
||||
ReleaseType = g.PrimaryType,
|
||||
Id = g.Id,
|
||||
Title = g.Title,
|
||||
ReleaseDate = g.FirstReleaseDate,
|
||||
};
|
||||
|
||||
await RunSearchRules(release);
|
||||
info.ReleaseGroups.Add(release);
|
||||
}
|
||||
|
||||
info.Links = GetLinksForArtist(artist);
|
||||
info.Members = GetBandMembers(artist);
|
||||
|
||||
if (lidarrArtistTask != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var artistResult = await lidarrArtistTask;
|
||||
info.Banner = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("banner", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.Logo = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("logo", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.Poster = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("poster", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.FanArt = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("fanart", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.Overview = artistResult.overview;
|
||||
try
|
||||
{
|
||||
var artistResult = await lidarrArtistTask;
|
||||
info.Banner = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("banner", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.Logo = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("logo", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.Poster = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("poster", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.FanArt = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("fanart", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.Overview = artistResult.overview;
|
||||
info.Name = artistResult.artistName;
|
||||
info.Monitored = artistResult.monitored;
|
||||
}
|
||||
catch (JsonSerializationException)
|
||||
{
|
||||
// swallow, Lidarr probably doesn't have this artist
|
||||
}
|
||||
}
|
||||
catch (JsonSerializationException)
|
||||
}
|
||||
|
||||
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public async Task<AlbumInformation> GetAlbumInformation(string albumId)
|
||||
{
|
||||
var lidarrSettings = await GetLidarrSettings();
|
||||
Task<AlbumLookup> lidarrAlbumTask = null;
|
||||
var info = new AlbumInformation { };
|
||||
if (lidarrSettings.Enabled)
|
||||
{
|
||||
lidarrAlbumTask = _lidarrApi.GetAlbumByForeignId(albumId, lidarrSettings.ApiKey, lidarrSettings.FullUri);
|
||||
|
||||
if (lidarrAlbumTask != null)
|
||||
{
|
||||
// swallow, Lidarr probably doesn't have this artist
|
||||
try
|
||||
{
|
||||
var albumResult = await lidarrAlbumTask;
|
||||
info.Cover = albumResult.images?.FirstOrDefault(x => x.coverType.Equals("cover", StringComparison.InvariantCultureIgnoreCase))?.url.ToHttpsUrl();
|
||||
info.Title = albumResult.title;
|
||||
info.Disambiguation = albumResult.disambiguation;
|
||||
info.Overview = albumResult.overview;
|
||||
info.Monitored = albumResult.monitored;
|
||||
info.Id = albumResult.foreignAlbumId;
|
||||
}
|
||||
catch (JsonSerializationException)
|
||||
{
|
||||
// swallow, Lidarr probably doesn't have this album
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,24 +129,24 @@ namespace Ombi.Core.Engine.V2
|
|||
|
||||
public async Task<AlbumArt> GetReleaseGroupArt(string musicBrainzId, CancellationToken token)
|
||||
{
|
||||
var art = await _musicBrainzApi.GetCoverArtForReleaseGroup(musicBrainzId, token);
|
||||
// var art = await _musicBrainzApi.GetCoverArtForReleaseGroup(musicBrainzId, token);
|
||||
|
||||
if (art == null || !art.images.Any())
|
||||
{
|
||||
return new AlbumArt();
|
||||
}
|
||||
// if (art == null || !art.images.Any())
|
||||
// {
|
||||
// return new AlbumArt();
|
||||
// }
|
||||
|
||||
foreach (var cover in art.images)
|
||||
{
|
||||
if ((cover.thumbnails?.small ?? string.Empty).HasValue())
|
||||
{
|
||||
return new AlbumArt(cover.thumbnails.small.ToHttpsUrl());
|
||||
}
|
||||
if ((cover.thumbnails?.large ?? string.Empty).HasValue())
|
||||
{
|
||||
return new AlbumArt(cover.thumbnails.large.ToHttpsUrl());
|
||||
}
|
||||
}
|
||||
// foreach (var cover in art.images)
|
||||
// {
|
||||
// if ((cover.thumbnails?.small ?? string.Empty).HasValue())
|
||||
// {
|
||||
// return new AlbumArt(cover.thumbnails.small.ToHttpsUrl());
|
||||
// }
|
||||
// if ((cover.thumbnails?.large ?? string.Empty).HasValue())
|
||||
// {
|
||||
// return new AlbumArt(cover.thumbnails.large.ToHttpsUrl());
|
||||
// }
|
||||
// }
|
||||
|
||||
return new AlbumArt();
|
||||
}
|
||||
|
@ -151,18 +160,18 @@ namespace Ombi.Core.Engine.V2
|
|||
private List<BandMember> GetBandMembers(Artist artist)
|
||||
{
|
||||
var members = new List<BandMember>();
|
||||
var membersOfBand = artist.Relations.Where(x => x.TypeId == RelationLinks.BandMember);
|
||||
foreach (var member in membersOfBand)
|
||||
{
|
||||
members.Add(new BandMember
|
||||
{
|
||||
Name = member.Artist?.Name,
|
||||
Attributes = member.Attributes,
|
||||
IsCurrentMember = member.Ended == null,
|
||||
End = member.End,
|
||||
Start = member.Begin
|
||||
});
|
||||
}
|
||||
// var membersOfBand = artist.Relations.Where(x => x.TypeId == RelationLinks.BandMember);
|
||||
// foreach (var member in membersOfBand)
|
||||
// {
|
||||
// members.Add(new BandMember
|
||||
// {
|
||||
// Name = member.Artist?.Name,
|
||||
// Attributes = member.Attributes,
|
||||
// IsCurrentMember = member.Ended == null,
|
||||
// End = member.End,
|
||||
// Start = member.Begin
|
||||
// });
|
||||
// }
|
||||
|
||||
return members;
|
||||
}
|
||||
|
@ -170,79 +179,79 @@ namespace Ombi.Core.Engine.V2
|
|||
private ArtistLinks GetLinksForArtist(Artist artist)
|
||||
{
|
||||
var links = new ArtistLinks();
|
||||
foreach (var relation in artist.Relations)
|
||||
{
|
||||
switch (relation.TypeId)
|
||||
{
|
||||
case RelationLinks.AllMusic:
|
||||
links.AllMusic = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.BbcMusic:
|
||||
links.BbcMusic = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.Discogs:
|
||||
links.Discogs = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.Homepage:
|
||||
links.HomePage = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.Imdb:
|
||||
links.Imdb = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.LastFm:
|
||||
links.LastFm = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.MySpace:
|
||||
links.MySpace = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.OnlineCommunity:
|
||||
links.OnlineCommunity = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.SocialNetwork:
|
||||
if ((relation.Url?.Resource ?? string.Empty).Contains("twitter", CompareOptions.IgnoreCase))
|
||||
{
|
||||
links.Twitter = relation.Url?.Resource.ToHttpsUrl();
|
||||
}
|
||||
if ((relation.Url?.Resource ?? string.Empty).Contains("facebook", CompareOptions.IgnoreCase))
|
||||
{
|
||||
links.Facebook = relation.Url?.Resource.ToHttpsUrl();
|
||||
}
|
||||
if ((relation.Url?.Resource ?? string.Empty).Contains("instagram", CompareOptions.IgnoreCase))
|
||||
{
|
||||
links.Instagram = relation.Url?.Resource.ToHttpsUrl();
|
||||
}
|
||||
if ((relation.Url?.Resource ?? string.Empty).Contains("vk", CompareOptions.IgnoreCase))
|
||||
{
|
||||
links.Vk = relation.Url?.Resource.ToHttpsUrl();
|
||||
}
|
||||
break;
|
||||
case RelationLinks.Streams:
|
||||
if ((relation.Url?.Resource ?? string.Empty).Contains("spotify", CompareOptions.IgnoreCase))
|
||||
{
|
||||
links.Spotify = relation.Url?.Resource.ToHttpsUrl();
|
||||
}
|
||||
if ((relation.Url?.Resource ?? string.Empty).Contains("deezer", CompareOptions.IgnoreCase))
|
||||
{
|
||||
links.Deezer = relation.Url?.Resource.ToHttpsUrl();
|
||||
}
|
||||
// foreach (var relation in artist.Relations)
|
||||
// {
|
||||
// switch (relation.TypeId)
|
||||
// {
|
||||
// case RelationLinks.AllMusic:
|
||||
// links.AllMusic = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.BbcMusic:
|
||||
// links.BbcMusic = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.Discogs:
|
||||
// links.Discogs = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.Homepage:
|
||||
// links.HomePage = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.Imdb:
|
||||
// links.Imdb = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.LastFm:
|
||||
// links.LastFm = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.MySpace:
|
||||
// links.MySpace = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.OnlineCommunity:
|
||||
// links.OnlineCommunity = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.SocialNetwork:
|
||||
// if ((relation.Url?.Resource ?? string.Empty).Contains("twitter", CompareOptions.IgnoreCase))
|
||||
// {
|
||||
// links.Twitter = relation.Url?.Resource.ToHttpsUrl();
|
||||
// }
|
||||
// if ((relation.Url?.Resource ?? string.Empty).Contains("facebook", CompareOptions.IgnoreCase))
|
||||
// {
|
||||
// links.Facebook = relation.Url?.Resource.ToHttpsUrl();
|
||||
// }
|
||||
// if ((relation.Url?.Resource ?? string.Empty).Contains("instagram", CompareOptions.IgnoreCase))
|
||||
// {
|
||||
// links.Instagram = relation.Url?.Resource.ToHttpsUrl();
|
||||
// }
|
||||
// if ((relation.Url?.Resource ?? string.Empty).Contains("vk", CompareOptions.IgnoreCase))
|
||||
// {
|
||||
// links.Vk = relation.Url?.Resource.ToHttpsUrl();
|
||||
// }
|
||||
// break;
|
||||
// case RelationLinks.Streams:
|
||||
// if ((relation.Url?.Resource ?? string.Empty).Contains("spotify", CompareOptions.IgnoreCase))
|
||||
// {
|
||||
// links.Spotify = relation.Url?.Resource.ToHttpsUrl();
|
||||
// }
|
||||
// if ((relation.Url?.Resource ?? string.Empty).Contains("deezer", CompareOptions.IgnoreCase))
|
||||
// {
|
||||
// links.Deezer = relation.Url?.Resource.ToHttpsUrl();
|
||||
// }
|
||||
|
||||
break;
|
||||
case RelationLinks.YouTube:
|
||||
links.YouTube = relation.Url?.Resource.ToHttpsUrl();
|
||||
break;
|
||||
case RelationLinks.Download:
|
||||
if ((relation.Url?.Resource ?? string.Empty).Contains("google", CompareOptions.IgnoreCase))
|
||||
{
|
||||
links.Google = relation.Url?.Resource.ToHttpsUrl();
|
||||
}
|
||||
if ((relation.Url?.Resource ?? string.Empty).Contains("apple", CompareOptions.IgnoreCase))
|
||||
{
|
||||
links.Apple = relation.Url?.Resource.ToHttpsUrl();
|
||||
}
|
||||
// break;
|
||||
// case RelationLinks.YouTube:
|
||||
// links.YouTube = relation.Url?.Resource.ToHttpsUrl();
|
||||
// break;
|
||||
// case RelationLinks.Download:
|
||||
// if ((relation.Url?.Resource ?? string.Empty).Contains("google", CompareOptions.IgnoreCase))
|
||||
// {
|
||||
// links.Google = relation.Url?.Resource.ToHttpsUrl();
|
||||
// }
|
||||
// if ((relation.Url?.Resource ?? string.Empty).Contains("apple", CompareOptions.IgnoreCase))
|
||||
// {
|
||||
// links.Apple = relation.Url?.Resource.ToHttpsUrl();
|
||||
// }
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
return links;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Ombi.Core
|
|||
});
|
||||
}
|
||||
|
||||
public async Task NewRequest(AlbumRequest model)
|
||||
public async Task NewRequest(MusicRequests model)
|
||||
{
|
||||
var notificationModel = new NotificationOptions
|
||||
{
|
||||
|
@ -55,7 +55,6 @@ namespace Ombi.Core
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
public async Task Notify(MovieRequests model, NotificationType type)
|
||||
{
|
||||
var notificationModel = new NotificationOptions
|
||||
|
@ -88,7 +87,7 @@ namespace Ombi.Core
|
|||
});
|
||||
}
|
||||
|
||||
public async Task Notify(AlbumRequest model, NotificationType type)
|
||||
public async Task Notify(MusicRequests model, NotificationType type)
|
||||
{
|
||||
var notificationModel = new NotificationOptions
|
||||
{
|
||||
|
|
|
@ -4,5 +4,16 @@
|
|||
{
|
||||
public string ForeignAlbumId { get; set; }
|
||||
public string RequestedByAlias { get; set; }
|
||||
public string Monitor { get; set; }
|
||||
public bool SearchForMissingAlbums { get; set; }
|
||||
}
|
||||
|
||||
public class MusicArtistRequestViewModel
|
||||
{
|
||||
public string ForeignArtistId { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public string RequestedByAlias { get; set; }
|
||||
public string Monitor { get; set; }
|
||||
public bool SearchForMissingAlbums { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,5 +7,6 @@
|
|||
public string Title { get; set; }
|
||||
public string Poster { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
}
|
||||
}
|
20
src/Ombi.Core/Models/Search/V2/Music/AlbumInformation.cs
Normal file
20
src/Ombi.Core/Models/Search/V2/Music/AlbumInformation.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ombi.Core.Models.Search.V2.Music
|
||||
{
|
||||
public class AlbumInformation
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Id { get; set; }
|
||||
public string StartYear { get; set; }
|
||||
public string EndYear { get; set; }
|
||||
public bool IsEnded => string.IsNullOrEmpty(EndYear);
|
||||
public bool Monitored { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Country { get; set; }
|
||||
public string Region { get; set; }
|
||||
public string Disambiguation { get; set; }
|
||||
public string Cover { get; set; }
|
||||
public string Overview { get; set; }
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ namespace Ombi.Core.Models.Search.V2.Music
|
|||
public string Poster { get; set; }
|
||||
public string FanArt { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public List<ReleaseGroup> ReleaseGroups { get; set; }
|
||||
public ArtistLinks Links { get; set; }
|
||||
public List<BandMember> Members { get; set; }
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.0" />
|
||||
<PackageReference Include="MusicBrainzAPI" Version="2.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="System.Diagnostics.Process" Version="4.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
@ -27,7 +26,6 @@
|
|||
<ProjectReference Include="..\Ombi.Api.Jellyfin\Ombi.Api.Jellyfin.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.FanartTv\Ombi.Api.FanartTv.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.MusicBrainz\Ombi.Api.MusicBrainz.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Radarr\Ombi.Api.Radarr.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.SickRage\Ombi.Api.SickRage.csproj" />
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Ombi.Core.Senders
|
|||
{
|
||||
public interface IMusicSender
|
||||
{
|
||||
Task<SenderResult> Send(AlbumRequest model);
|
||||
Task<SenderResult> SendAlbum(MusicRequests model);
|
||||
Task<SenderResult> SendArtist(MusicRequests model);
|
||||
}
|
||||
}
|
|
@ -10,10 +10,10 @@ namespace Ombi.Core
|
|||
{
|
||||
Task NewRequest(FullBaseRequest model);
|
||||
Task NewRequest(ChildRequests model);
|
||||
Task NewRequest(AlbumRequest model);
|
||||
Task NewRequest(MusicRequests model);
|
||||
Task Notify(MovieRequests model, NotificationType type);
|
||||
Task Notify(ChildRequests model, NotificationType type);
|
||||
Task Notify(AlbumRequest model, NotificationType type);
|
||||
Task Notify(MusicRequests model, NotificationType type);
|
||||
Task Notify(NotificationOptions model);
|
||||
}
|
||||
}
|
|
@ -33,14 +33,14 @@ namespace Ombi.Core.Senders
|
|||
private readonly IRepository<RequestQueue> _requestQueueRepository;
|
||||
private readonly INotificationHelper _notificationHelper;
|
||||
|
||||
public async Task<SenderResult> Send(AlbumRequest model)
|
||||
public async Task<SenderResult> SendAlbum(MusicRequests model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await _lidarrSettings.GetSettingsAsync();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
return await SendToLidarr(model, settings);
|
||||
return await SendAlbumToLidarr(model, settings);
|
||||
}
|
||||
|
||||
return new SenderResult { Success = false, Sent = false, Message = "Lidarr is not enabled" };
|
||||
|
@ -73,7 +73,47 @@ namespace Ombi.Core.Senders
|
|||
return new SenderResult { Success = false, Sent = false, Message = "Something went wrong!" };
|
||||
}
|
||||
|
||||
private async Task<SenderResult> SendToLidarr(AlbumRequest model, LidarrSettings settings)
|
||||
public async Task<SenderResult> SendArtist(MusicRequests model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = await _lidarrSettings.GetSettingsAsync();
|
||||
if (settings.Enabled)
|
||||
{
|
||||
return await SendArtistToLidarr(model, settings);
|
||||
}
|
||||
|
||||
return new SenderResult { Success = false, Sent = false, Message = "Lidarr is not enabled" };
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_log.LogError(e, "Exception thrown when sending a music to DVR app, added to the request queue");
|
||||
var existingQueue = await _requestQueueRepository.FirstOrDefaultAsync(x => x.RequestId == model.Id);
|
||||
if (existingQueue != null)
|
||||
{
|
||||
existingQueue.RetryCount++;
|
||||
existingQueue.Error = e.Message;
|
||||
await _requestQueueRepository.SaveChangesAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await _requestQueueRepository.Add(new RequestQueue
|
||||
{
|
||||
Dts = DateTime.UtcNow,
|
||||
Error = e.Message,
|
||||
RequestId = model.Id,
|
||||
Type = RequestType.Album,
|
||||
RetryCount = 0
|
||||
});
|
||||
await _notificationHelper.Notify(model, NotificationType.ItemAddedToFaultQueue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new SenderResult { Success = false, Sent = false, Message = "Something went wrong!" };
|
||||
}
|
||||
|
||||
private async Task<SenderResult> SendAlbumToLidarr(MusicRequests model, LidarrSettings settings)
|
||||
{
|
||||
var qualityToUse = int.Parse(settings.DefaultQualityProfile);
|
||||
//if (model.QualityOverride > 0)
|
||||
|
@ -99,9 +139,9 @@ namespace Ombi.Core.Senders
|
|||
foreignArtistId = model.ForeignArtistId,
|
||||
addOptions = new Addoptions
|
||||
{
|
||||
monitored = true,
|
||||
monitor = MonitorTypes.None,
|
||||
searchForMissingAlbums = false,
|
||||
monitored = model.Monitored,
|
||||
monitor = model.Monitor,
|
||||
searchForMissingAlbums = model.SearchForMissingAlbums,
|
||||
AlbumsToMonitor = new[] {model.ForeignAlbumId}
|
||||
},
|
||||
added = DateTime.Now,
|
||||
|
@ -160,7 +200,46 @@ namespace Ombi.Core.Senders
|
|||
return new SenderResult { Success = false, Sent = false, Message = "Album is already monitored" };
|
||||
}
|
||||
|
||||
private async Task<SenderResult> SetupAlbum(AlbumRequest model, ArtistResult artist, LidarrSettings settings)
|
||||
private async Task<SenderResult> SendArtistToLidarr(MusicRequests model, LidarrSettings settings)
|
||||
{
|
||||
var qualityToUse = int.Parse(settings.DefaultQualityProfile);
|
||||
//if (model.QualityOverride > 0)
|
||||
//{
|
||||
// qualityToUse = model.QualityOverride;
|
||||
//}
|
||||
|
||||
var rootFolderPath = /*model.RootPathOverride <= 0 ?*/ settings.DefaultRootPath /*: await RadarrRootPath(model.RootPathOverride, settings)*/;
|
||||
|
||||
EnsureArg.IsNotNullOrEmpty(model.ForeignArtistId, nameof(model.ForeignArtistId));
|
||||
EnsureArg.IsNotNullOrEmpty(rootFolderPath, nameof(rootFolderPath));
|
||||
|
||||
// Create artist
|
||||
var newArtist = new ArtistAdd
|
||||
{
|
||||
foreignArtistId = model.ForeignArtistId,
|
||||
addOptions = new Addoptions
|
||||
{
|
||||
monitor = model.Monitor,
|
||||
searchForMissingAlbums = model.SearchForMissingAlbums
|
||||
},
|
||||
artistName = model.ArtistName,
|
||||
added = DateTime.Now,
|
||||
monitored = model.Monitored,
|
||||
metadataProfileId = settings.MetadataProfileId,
|
||||
qualityProfileId = qualityToUse,
|
||||
rootFolderPath = rootFolderPath,
|
||||
};
|
||||
// Console.Write(newArtist);
|
||||
var result = await _lidarrApi.AddArtist(newArtist, settings.ApiKey, settings.FullUri);
|
||||
if (result != null && result.id > 0)
|
||||
{
|
||||
return new SenderResult { Message = "Artist has been requested!", Sent = true, Success = true };
|
||||
}
|
||||
|
||||
return new SenderResult { Success = false, Sent = false, Message = "Artist is already monitored" };
|
||||
}
|
||||
|
||||
private async Task<SenderResult> SetupAlbum(MusicRequests model, ArtistResult artist, LidarrSettings settings)
|
||||
{
|
||||
// Get the album id
|
||||
var albums = await _lidarrApi.GetAllAlbumsByArtistId(artist.id, settings.ApiKey, settings.FullUri);
|
||||
|
|
|
@ -261,7 +261,7 @@ namespace Ombi.Core.Senders
|
|||
qualityProfileId = qualityToUse,
|
||||
titleSlug = model.ParentRequest.Title,
|
||||
seriesType = seriesType,
|
||||
addOptions = new AddOptions
|
||||
addOptions = new Ombi.Api.Sonarr.Models.AddOptions
|
||||
{
|
||||
ignoreEpisodesWithFiles = false, // There shouldn't be any episodes with files, this is a new season
|
||||
ignoreEpisodesWithoutFiles = false, // We want all missing
|
||||
|
|
|
@ -63,7 +63,6 @@ using Ombi.Schedule.Jobs.Plex.Interfaces;
|
|||
using Ombi.Schedule.Jobs.SickRage;
|
||||
using Ombi.Schedule.Processor;
|
||||
using Quartz.Spi;
|
||||
using Ombi.Api.MusicBrainz;
|
||||
using Ombi.Api.Twilio;
|
||||
using Ombi.Api.CloudService;
|
||||
using Ombi.Api.RottenTomatoes;
|
||||
|
@ -166,7 +165,6 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<IOneSignalApi, OneSignalApi>();
|
||||
services.AddTransient<ILidarrApi, LidarrApi>();
|
||||
services.AddTransient<IGroupMeApi, GroupMeApi>();
|
||||
services.AddTransient<IMusicBrainzApi, MusicBrainzApi>();
|
||||
services.AddTransient<IWhatsAppApi, WhatsAppApi>();
|
||||
services.AddTransient<ICloudMobileNotification, CloudMobileNotification>();
|
||||
services.AddTransient<IEmbyApiFactory, EmbyApiFactory>();
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
<ProjectReference Include="..\Ombi.Api.GroupMe\Ombi.Api.GroupMe.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Lidarr\Ombi.Api.Lidarr.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Mattermost\Ombi.Api.Mattermost.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.MusicBrainz\Ombi.Api.MusicBrainz.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Notifications\Ombi.Api.Notifications.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Plex\Ombi.Api.Plex.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Api.Pushbullet\Ombi.Api.Pushbullet.csproj" />
|
||||
|
|
|
@ -163,7 +163,7 @@ namespace Ombi.Notifications.Tests
|
|||
public void MusicNotificationTests()
|
||||
{
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<AlbumRequest>()
|
||||
var req = F.Build<MusicRequests>()
|
||||
.With(x => x.RequestType, RequestType.Album)
|
||||
.With(x => x.Available, true)
|
||||
.Create();
|
||||
|
@ -198,7 +198,7 @@ namespace Ombi.Notifications.Tests
|
|||
public string MusicNotificationTests_RequestStatus(bool available, bool denied, bool approved)
|
||||
{
|
||||
var notificationOptions = new NotificationOptions();
|
||||
var req = F.Build<AlbumRequest>()
|
||||
var req = F.Build<MusicRequests>()
|
||||
.With(x => x.RequestType, RequestType.Album)
|
||||
.With(x => x.Available, available)
|
||||
.With(x => x.Denied, denied)
|
||||
|
|
|
@ -46,7 +46,8 @@ namespace Ombi.Notifications
|
|||
|
||||
|
||||
protected ChildRequests TvRequest { get; set; }
|
||||
protected AlbumRequest AlbumRequest { get; set; }
|
||||
protected MusicRequests AlbumRequest { get; set; }
|
||||
protected MusicRequests ArtistRequest { get; set; }
|
||||
protected MovieRequests MovieRequest { get; set; }
|
||||
protected IQueryable<OmbiUser> Subscribed { get; private set; }
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace Ombi.Notifications
|
|||
CalculateRequestStatus(req);
|
||||
}
|
||||
|
||||
public void Setup(NotificationOptions opts, AlbumRequest req, CustomizationSettings s,
|
||||
public void Setup(NotificationOptions opts, MusicRequests req, CustomizationSettings s,
|
||||
UserNotificationPreferences pref)
|
||||
{
|
||||
LoadIssues(opts);
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace Ombi.Schedule.Jobs.Lidarr
|
|||
await _notification.Clients.Clients(NotificationHub.AdminConnectionIds)
|
||||
.SendAsync(NotificationHub.NotificationEvent, "Lidarr Availability Check Started");
|
||||
var allAlbumRequests = _requestRepository.GetAll().Include(x => x.RequestedUser).Where(x => !x.Available);
|
||||
var albumsToUpdate = new List<AlbumRequest>();
|
||||
var albumsToUpdate = new List<MusicRequests>();
|
||||
foreach (var request in allAlbumRequests)
|
||||
{
|
||||
// Check if we have it cached
|
||||
|
|
|
@ -81,7 +81,23 @@ namespace Ombi.Schedule.Jobs.Ombi
|
|||
await _requestQueue.SaveChangesAsync();
|
||||
continue;
|
||||
}
|
||||
var result = await _musicSender.Send(musicRequest);
|
||||
var result = await _musicSender.SendAlbum(musicRequest);
|
||||
if (result.Success)
|
||||
{
|
||||
request.Completed = DateTime.UtcNow;
|
||||
await _requestQueue.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
if (request.Type == RequestType.Artist)
|
||||
{
|
||||
var musicRequest = await _musicRequestRepository.GetAll().FirstOrDefaultAsync(x => x.Id == request.RequestId);
|
||||
if (musicRequest == null)
|
||||
{
|
||||
await _requestQueue.Delete(request);
|
||||
await _requestQueue.SaveChangesAsync();
|
||||
continue;
|
||||
}
|
||||
var result = await _musicSender.SendArtist(musicRequest);
|
||||
if (result.Success)
|
||||
{
|
||||
request.Completed = DateTime.UtcNow;
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace Ombi.Store.Context
|
|||
public DbSet<NotificationTemplates> NotificationTemplates { get; set; }
|
||||
|
||||
public DbSet<MovieRequests> MovieRequests { get; set; }
|
||||
public DbSet<AlbumRequest> AlbumRequests { get; set; }
|
||||
public DbSet<MusicRequests> MusicRequests { get; set; }
|
||||
public DbSet<TvRequests> TvRequests { get; set; }
|
||||
public DbSet<ChildRequests> ChildRequests { get; set; }
|
||||
public DbSet<EpisodeRequests> EpisodeRequests { get; set; }
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
TvShow = 0,
|
||||
Movie = 1,
|
||||
Album = 2,
|
||||
Artist = 3
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||
|
||||
namespace Ombi.Store.Entities.Requests
|
||||
{
|
||||
[Table("AlbumRequests")]
|
||||
public class AlbumRequest : BaseRequest
|
||||
[Table("MusicRequests")]
|
||||
public class MusicRequests : BaseRequest
|
||||
{
|
||||
public string ForeignAlbumId { get; set; }
|
||||
public string ForeignArtistId { get; set; }
|
||||
|
@ -17,6 +17,9 @@ namespace Ombi.Store.Entities.Requests
|
|||
public bool Subscribed { get; set; }
|
||||
[NotMapped]
|
||||
public bool ShowSubscribe { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public string Monitor { get; set; }
|
||||
public bool SearchForMissingAlbums { get; set; }
|
||||
|
||||
|
||||
[NotMapped]
|
1243
src/Ombi.Store/Migrations/OmbiMySql/20210802192907_RenameAlbumRequests.Designer.cs
generated
Normal file
1243
src/Ombi.Store/Migrations/OmbiMySql/20210802192907_RenameAlbumRequests.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,17 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ombi.Store.Migrations.OmbiMySql
|
||||
{
|
||||
public partial class RenameAlbumRequests : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.RenameTable("AlbumRequests", null, "MusicRequests");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
1243
src/Ombi.Store/Migrations/OmbiMySql/20210802193833_MusicRequestsMonitor.Designer.cs
generated
Normal file
1243
src/Ombi.Store/Migrations/OmbiMySql/20210802193833_MusicRequestsMonitor.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,46 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ombi.Store.Migrations.OmbiMySql
|
||||
{
|
||||
public partial class MusicRequestsMonitor : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Monitored",
|
||||
table: "MusicRequests",
|
||||
type: "BOOLEAN",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Monitor",
|
||||
table: "MusicRequests",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SearchForMissingAlbums",
|
||||
table: "MusicRequests",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Monitored",
|
||||
table: "MusicRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Monitor",
|
||||
table: "MusicRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SearchForMissingAlbums",
|
||||
table: "MusicRequests");
|
||||
}
|
||||
}
|
||||
}
|
1243
src/Ombi.Store/Migrations/OmbiSqlite/20210802192907_RenameAlbumRequests.Designer.cs
generated
Normal file
1243
src/Ombi.Store/Migrations/OmbiSqlite/20210802192907_RenameAlbumRequests.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,17 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ombi.Store.Migrations.OmbiSqlite
|
||||
{
|
||||
public partial class RenameAlbumRequests : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.RenameTable("AlbumRequests", null, "MusicRequests");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
1243
src/Ombi.Store/Migrations/OmbiSqlite/20210802193833_MusicRequestsMonitor.Designer.cs
generated
Normal file
1243
src/Ombi.Store/Migrations/OmbiSqlite/20210802193833_MusicRequestsMonitor.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,46 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Ombi.Store.Migrations.OmbiSqlite
|
||||
{
|
||||
public partial class MusicRequestsMonitor : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Monitored",
|
||||
table: "MusicRequests",
|
||||
type: "BOOLEAN",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Monitor",
|
||||
table: "MusicRequests",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SearchForMissingAlbums",
|
||||
table: "MusicRequests",
|
||||
type: "longtext",
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Monitored",
|
||||
table: "MusicRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Monitor",
|
||||
table: "MusicRequests");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SearchForMissingAlbums",
|
||||
table: "MusicRequests");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -418,76 +418,6 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.ToTable("RequestSubscription");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.AlbumRequest", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Approved")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ArtistName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Available")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Cover")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool?>("Denied")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DeniedReason")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Disk")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ForeignAlbumId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ForeignArtistId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("MarkedAsApproved")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("MarkedAsAvailable")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("MarkedAsDenied")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<decimal>("Rating")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RequestType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("RequestedByAlias")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("RequestedDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RequestedUserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("AlbumRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -727,6 +657,85 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.ToTable("MovieRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MusicRequests", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Approved")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ArtistName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Available")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Cover")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool?>("Denied")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DeniedReason")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Disk")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ForeignAlbumId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ForeignArtistId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("MarkedAsApproved")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("MarkedAsAvailable")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("MarkedAsDenied")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Monitor")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("Monitored")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<decimal>("Rating")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("ReleaseDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RequestType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("RequestedByAlias")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("RequestedDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RequestedUserId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("SearchForMissingAlbums")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedUserId");
|
||||
|
||||
b.ToTable("MusicRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -1051,15 +1060,6 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.AlbumRequest", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
|
||||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.ChildRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.Requests.TvRequests", "ParentRequest")
|
||||
|
@ -1126,6 +1126,15 @@ namespace Ombi.Store.Migrations.OmbiSqlite
|
|||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.MusicRequests", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "RequestedUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedUserId");
|
||||
|
||||
b.Navigation("RequestedUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Ombi.Store.Entities.Requests.RequestLog", b =>
|
||||
{
|
||||
b.HasOne("Ombi.Store.Entities.OmbiUser", "User")
|
||||
|
|
|
@ -4,14 +4,14 @@ using Ombi.Store.Entities.Requests;
|
|||
|
||||
namespace Ombi.Store.Repository.Requests
|
||||
{
|
||||
public interface IMusicRequestRepository : IRepository<AlbumRequest>
|
||||
public interface IMusicRequestRepository : IRepository<MusicRequests>
|
||||
{
|
||||
IQueryable<AlbumRequest> GetAll(string userId);
|
||||
AlbumRequest GetRequest(string foreignAlbumId);
|
||||
Task<AlbumRequest> GetRequestAsync(string foreignAlbumId);
|
||||
IQueryable<AlbumRequest> GetWithUser();
|
||||
IQueryable<AlbumRequest> GetWithUser(string userId);
|
||||
IQueryable<MusicRequests> GetAll(string userId);
|
||||
MusicRequests GetRequest(string foreignAlbumId);
|
||||
Task<MusicRequests> GetRequestAsync(string foreignAlbumId);
|
||||
IQueryable<MusicRequests> GetWithUser();
|
||||
IQueryable<MusicRequests> GetWithUser(string userId);
|
||||
Task Save();
|
||||
Task Update(AlbumRequest request);
|
||||
Task Update(MusicRequests request);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ using Ombi.Store.Entities.Requests;
|
|||
|
||||
namespace Ombi.Store.Repository.Requests
|
||||
{
|
||||
public class MusicRequestRepository : Repository<AlbumRequest>, IMusicRequestRepository
|
||||
public class MusicRequestRepository : Repository<MusicRequests>, IMusicRequestRepository
|
||||
{
|
||||
public MusicRequestRepository(OmbiContext ctx) : base(ctx)
|
||||
{
|
||||
|
@ -18,48 +18,58 @@ namespace Ombi.Store.Repository.Requests
|
|||
|
||||
private OmbiContext Db { get; }
|
||||
|
||||
public Task<AlbumRequest> GetRequestAsync(string foreignAlbumId)
|
||||
public Task<MusicRequests> GetRequestAsync(string foreignAlbumId)
|
||||
{
|
||||
return Db.AlbumRequests.Where(x => x.ForeignAlbumId == foreignAlbumId)
|
||||
return Db.MusicRequests.Where(x => x.ForeignAlbumId == foreignAlbumId)
|
||||
.Include(x => x.RequestedUser)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public IQueryable<AlbumRequest> GetAll(string userId)
|
||||
public IQueryable<MusicRequests> GetAll(string userId)
|
||||
{
|
||||
return GetWithUser().Where(x => x.RequestedUserId == userId);
|
||||
}
|
||||
|
||||
public AlbumRequest GetRequest(string foreignAlbumId)
|
||||
public MusicRequests GetRequest(string foreignAlbumId)
|
||||
{
|
||||
return Db.AlbumRequests.Where(x => x.ForeignAlbumId == foreignAlbumId)
|
||||
return Db.MusicRequests.Where(x => x.ForeignAlbumId == foreignAlbumId)
|
||||
.Include(x => x.RequestedUser)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public IQueryable<AlbumRequest> GetWithUser()
|
||||
public IQueryable<MusicRequests> GetWithUser()
|
||||
{
|
||||
return Db.AlbumRequests
|
||||
return Db.MusicRequests
|
||||
.Include(x => x.RequestedUser)
|
||||
.ThenInclude(x => x.NotificationUserIds)
|
||||
.AsQueryable();
|
||||
}
|
||||
|
||||
|
||||
public IQueryable<AlbumRequest> GetWithUser(string userId)
|
||||
public IQueryable<MusicRequests> GetWithUser(string userId)
|
||||
{
|
||||
return Db.AlbumRequests
|
||||
return Db.MusicRequests
|
||||
.Where(x => x.RequestedUserId == userId)
|
||||
.Include(x => x.RequestedUser)
|
||||
.ThenInclude(x => x.NotificationUserIds)
|
||||
.AsQueryable();
|
||||
}
|
||||
|
||||
public async Task Update(AlbumRequest request)
|
||||
public async Task Update(MusicRequests request)
|
||||
{
|
||||
if (Db.Entry(request).State == EntityState.Detached)
|
||||
{
|
||||
Db.AlbumRequests.Attach(request);
|
||||
Db.MusicRequests.Attach(request);
|
||||
Db.Update(request);
|
||||
}
|
||||
await InternalSaveChanges();
|
||||
}
|
||||
|
||||
public async Task UpdateArtist(MusicRequests request)
|
||||
{
|
||||
if (Db.Entry(request).State == EntityState.Detached)
|
||||
{
|
||||
Db.MusicRequests.Attach(request);
|
||||
Db.Update(request);
|
||||
}
|
||||
await InternalSaveChanges();
|
||||
|
|
|
@ -112,8 +112,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Hubs", "Ombi.Hubs\Ombi
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.GroupMe", "Ombi.Api.GroupMe\Ombi.Api.GroupMe.csproj", "{9266403C-B04D-4C0F-AC39-82F12C781949}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.MusicBrainz", "Ombi.Api.MusicBrainz\Ombi.Api.MusicBrainz.csproj", "{C5C1769B-4197-4410-A160-0EEF39EDDC98}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.Api.Twilio", "Ombi.Api.Twilio\Ombi.Api.Twilio.csproj", "{34E5DD1A-6A90-448B-9E71-64D1ACD6C1A3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ombi.HealthChecks", "Ombi.HealthChecks\Ombi.HealthChecks.csproj", "{59D19538-0496-44EE-936E-EBBC22CF7B27}"
|
||||
|
@ -330,6 +328,10 @@ Global
|
|||
{8F19C701-7881-4BC7-8BBA-B068A6B954AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F19C701-7881-4BC7-8BBA-B068A6B954AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8F19C701-7881-4BC7-8BBA-B068A6B954AD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C81C423-25CC-4A91-ABE7-9C3F97770F69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C81C423-25CC-4A91-ABE7-9C3F97770F69}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C81C423-25CC-4A91-ABE7-9C3F97770F69}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0C81C423-25CC-4A91-ABE7-9C3F97770F69}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</div>
|
||||
<img [routerLink]="generateDetailsLink()" id="cardImage" src="{{result.posterPath}}" class="image"
|
||||
alt="{{result.title}}">
|
||||
<div [ngClass]="result.posterPath.includes('images/') ? 'middle-show' : 'middle'">
|
||||
<div [ngClass]="result.posterPath != null ? 'middle' : 'middle-show'">
|
||||
<a class="poster-overlay" [routerLink]="generateDetailsLink()">
|
||||
<div class="summary">
|
||||
<div class="title" id="title{{result.id}}">{{result.title}}</div>
|
||||
|
@ -19,13 +19,17 @@
|
|||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div [ngClass]="result.posterPath.includes('images/') ? 'button-request-container-show' : 'button-request-container'" class="row" *ngIf="!result.available && !result.approved && !result.requested">
|
||||
<div [ngClass]="result.posterPath != null ? 'button-request-container-show' : 'button-request-container'" class="row" *ngIf="!result.available && !result.approved && !result.requested">
|
||||
<div class="button-request poster-overlay">
|
||||
<button id="requestButton{{result.id}}{{result.type}}{{discoverType}}" *ngIf="requestable" mat-raised-button class="btn-ombi full-width poster-request-btn" (click)="request($event)">
|
||||
<i *ngIf="!loading" class="fa-lg fas fa-cloud-download-alt"></i>
|
||||
<i *ngIf="loading" class="fas fa-spinner fa-pulse fa-2x fa-fw" aria-hidden="true"></i>
|
||||
{{'Common.Request' | translate }}
|
||||
</button>
|
||||
<button id="requestButton{{result.id}}{{result.type}}{{discoverType}}" *ngIf="monitored" mat-raised-button
|
||||
class="btn-spacing full-width poster-request-btn" color="accent" [disabled]>
|
||||
<i class="fa-lg fas fa-check"></i> {{'Common.Monitored' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -3,6 +3,8 @@ import { IDiscoverCardResult } from "../../interfaces";
|
|||
import { RequestType } from "../../../interfaces";
|
||||
import { MessageService, RequestService, SearchV2Service } from "../../../services";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { IArtistRequestModel } from "../../../interfaces/IRequestModel";
|
||||
import { IReleaseGroups } from "../../../interfaces/IMusicSearchResultV2";
|
||||
import { ISearchTvResultV2 } from "../../../interfaces/ISearchTvResultV2";
|
||||
import { ISearchMovieResultV2 } from "../../../interfaces/ISearchMovieResultV2";
|
||||
import { EpisodeRequestComponent } from "../../../shared/episode-request/episode-request.component";
|
||||
|
@ -25,9 +27,11 @@ export class DiscoverCardComponent implements OnInit {
|
|||
public loading: boolean;
|
||||
|
||||
public requestable: boolean;
|
||||
public monitored: boolean;
|
||||
|
||||
// This data is needed to open the dialog
|
||||
private tvSearchResult: ISearchTvResultV2;
|
||||
private allAlbums: IReleaseGroups[] = [];
|
||||
|
||||
constructor(private searchService: SearchV2Service, private dialog: MatDialog, private requestService: RequestService,
|
||||
public messageService: MessageService) { }
|
||||
|
@ -40,6 +44,9 @@ export class DiscoverCardComponent implements OnInit {
|
|||
if (this.result.type == RequestType.movie) {
|
||||
this.getExtraMovieInfo();
|
||||
}
|
||||
if (this.result.type == RequestType.artist) {
|
||||
this.getArtistInformation();
|
||||
}
|
||||
if (this.result.type == RequestType.album) {
|
||||
this.getAlbumInformation();
|
||||
}
|
||||
|
@ -52,7 +59,7 @@ export class DiscoverCardComponent implements OnInit {
|
|||
this.updateTvItem(this.tvSearchResult);
|
||||
}
|
||||
|
||||
public async getAlbumInformation() {
|
||||
public async getArtistInformation() {
|
||||
this.searchService.getArtistInformation(this.result.id.toString()).subscribe(x => {
|
||||
if (x.poster) {
|
||||
this.result.posterPath = x.poster;
|
||||
|
@ -65,10 +72,35 @@ export class DiscoverCardComponent implements OnInit {
|
|||
}
|
||||
})
|
||||
}
|
||||
this.result.title = x.startYear ? `${x.name} (${x.startYear})` : x.name;
|
||||
this.result.title = x.name;
|
||||
this.result.overview = x.overview;
|
||||
this.fullyLoaded = true;
|
||||
this.requestable = true;
|
||||
if (x.monitored) {
|
||||
this.requestable = false;
|
||||
this.monitored = true;
|
||||
} else {
|
||||
this.requestable = true;
|
||||
this.monitored = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async getAlbumInformation() {
|
||||
this.searchService.getAlbumInformation(this.result.id.toString()).subscribe(x => {
|
||||
if (x.cover) {
|
||||
this.result.posterPath = x.cover;
|
||||
this.fullyLoaded = true;
|
||||
}
|
||||
this.result.title = x.title;
|
||||
this.result.overview = x.overview;
|
||||
this.fullyLoaded = true;
|
||||
if (x.monitored) {
|
||||
this.requestable = false;
|
||||
this.monitored = true;
|
||||
} else {
|
||||
this.requestable = true;
|
||||
this.monitored = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -78,8 +110,10 @@ export class DiscoverCardComponent implements OnInit {
|
|||
return `/details/movie/${this.result.id}`;
|
||||
case RequestType.tvShow:
|
||||
return `/details/tv/${this.result.id}`;
|
||||
case RequestType.album: //Actually artist
|
||||
case RequestType.artist: //Actually artist
|
||||
return `/details/artist/${this.result.id}`;
|
||||
case RequestType.album: //Actually artist
|
||||
return `/details/album/${this.result.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,6 +147,17 @@ export class DiscoverCardComponent implements OnInit {
|
|||
event.preventDefault();
|
||||
this.loading = true;
|
||||
switch (this.result.type) {
|
||||
case RequestType.artist:
|
||||
this.requestService.requestArtist({ foreignArtistId: this.result.id.toString(), monitored: true, monitor: "all", searchForMissingAlbums: true }).subscribe(x => {
|
||||
if (x.result) {
|
||||
this.result.requested = true;
|
||||
this.messageService.send(x.message, "Ok");
|
||||
} else {
|
||||
this.messageService.send(x.errorMessage, "Ok");
|
||||
}
|
||||
this.loading = false;
|
||||
});;
|
||||
return;
|
||||
case RequestType.tvShow:
|
||||
const dia = this.dialog.open(EpisodeRequestComponent, { width: "700px", data: { series: this.tvSearchResult, isAdmin: this.isAdmin }, panelClass: 'modal-panel' });
|
||||
dia.afterClosed().subscribe(x => this.loading = false);
|
||||
|
|
|
@ -90,6 +90,8 @@ export class DiscoverSearchResultsComponent implements OnInit {
|
|||
} else if (m.mediaType == "tv") {
|
||||
mediaType = RequestType.tvShow;
|
||||
} else if (m.mediaType == "Artist") {
|
||||
mediaType = RequestType.artist;
|
||||
} else if (m.mediaType == "Album") {
|
||||
mediaType = RequestType.album;
|
||||
}
|
||||
|
||||
|
@ -104,7 +106,7 @@ export class DiscoverSearchResultsComponent implements OnInit {
|
|||
}
|
||||
|
||||
this.discoverResults.push({
|
||||
posterPath: mediaType !== RequestType.album ? poster : "images/default-music-placeholder.png",
|
||||
posterPath: mediaType !== RequestType.artist && mediaType !== RequestType.album ? poster : "images/default-music-placeholder.png",
|
||||
requested: false,
|
||||
title: m.title,
|
||||
type: mediaType,
|
||||
|
|
|
@ -15,6 +15,29 @@ export interface IArtistSearchResult {
|
|||
links: IArtistLinks;
|
||||
members: IBandMembers[];
|
||||
overview: string;
|
||||
monitored: boolean;
|
||||
|
||||
background: any;
|
||||
}
|
||||
|
||||
export interface IAlbumSearchResult {
|
||||
title: string;
|
||||
id: string;
|
||||
startYear: string;
|
||||
endYear: string;
|
||||
type: string;
|
||||
country: string;
|
||||
region: string;
|
||||
disambiguation: string;
|
||||
banner: string;
|
||||
logo: string;
|
||||
cover: string;
|
||||
fanArt: string;
|
||||
releaseGroups: IReleaseGroups[];
|
||||
links: IArtistLinks;
|
||||
members: IBandMembers[];
|
||||
overview: string;
|
||||
monitored: boolean;
|
||||
|
||||
background: any;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
export enum RequestType {
|
||||
tvShow = 0,
|
||||
movie = 1,
|
||||
album = 2,
|
||||
artist = 2,
|
||||
album = 3
|
||||
}
|
||||
|
||||
// NEW WORLD
|
||||
|
@ -44,6 +45,16 @@ export interface IAlbumRequest extends IBaseRequest {
|
|||
|
||||
export interface IAlbumRequestModel {
|
||||
foreignAlbumId: string;
|
||||
monitored: boolean;
|
||||
monitor: string;
|
||||
searchForMissingAlbums: boolean;
|
||||
}
|
||||
|
||||
export interface IArtistRequestModel {
|
||||
foreignArtistId: string;
|
||||
monitored: boolean;
|
||||
monitor: string;
|
||||
searchForMissingAlbums: boolean;
|
||||
}
|
||||
|
||||
export interface IRequestsViewModel<T> {
|
||||
|
|
|
@ -80,7 +80,7 @@ export class IssuesDetailsComponent implements OnInit {
|
|||
this.router.navigate(['/details/movie/', firstIssue.providerId]);
|
||||
return;
|
||||
|
||||
case RequestType.album:
|
||||
case RequestType.artist:
|
||||
this.router.navigate(['/details/artist/', firstIssue.providerId]);
|
||||
return;
|
||||
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
<div *ngIf="!album" class="justify-content-md-center top-spacing loading-spinner">
|
||||
<mat-spinner [color]="'accent'"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<div *ngIf="album" class="dark-theme">
|
||||
|
||||
<top-banner [title]="album.title" [background]="getBackground()" [tagline]="album.disambiguation"></top-banner>
|
||||
|
||||
<section id="info-wrapper">
|
||||
<div class="small-middle-container">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<media-poster [posterPath]="album.cover"></media-poster>
|
||||
|
||||
<!--Next to poster-->
|
||||
<!-- <div class="col-12 col-lg-3 col-xl-3 media-row">
|
||||
|
||||
<social-icons [homepage]="artist.links?.homePage" [doNotAppend]="true" [imdbId]="artist.links?.imdb" [twitter]="artist.links?.twitter" [facebook]="artist.links?.facebook" [instagram]="artist.links?.instagram"></social-icons>
|
||||
|
||||
</div> -->
|
||||
|
||||
<div class="col-12 col-lg-6 col-xl-6 media-row">
|
||||
|
||||
<button *ngIf="!album.monitored" mat-raised-button class="btn-spacing" color="primary" (click)="requestAlbum()">
|
||||
<i class="fas fa-plus"></i> {{ 'MediaDetails.RequestAlbum' | translate }}</button>
|
||||
|
||||
|
||||
|
||||
<button mat-raised-button class="btn-green btn-spacing" *ngIf="album.monitored"> {{
|
||||
'Common.Requested' | translate }}</button>
|
||||
<span *ngIf="!album.monitored">
|
||||
<span *ngIf="album.monitored; then requestedBtn else notRequestedBtn"></span>
|
||||
|
||||
<!-- <ng-template #requestedBtn>
|
||||
<button mat-raised-button *ngIf="!hasRequest || hasRequest && movieRequest && !movieRequest.denied"
|
||||
class="btn-spacing" color="warn" [disabled]><i class="fas fa-check"></i>
|
||||
{{ 'Common.Requested' | translate }}</button>
|
||||
</ng-template>
|
||||
<ng-template #notRequestedBtn>
|
||||
<button mat-raised-button class="btn-spacing" color="primary" (click)="request()">
|
||||
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i> <i
|
||||
*ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
|
||||
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i> {{
|
||||
'Common.Request' | translate }}</button>
|
||||
<!-- </ng-template> -->
|
||||
</span>
|
||||
<!-- <span *ngIf="isAdmin && hasRequest">
|
||||
<button (click)="approve()" mat-raised-button class="btn-spacing" color="accent">
|
||||
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
|
||||
</button>
|
||||
<button *ngIf="!movie.available" (click)="markAvailable()" mat-raised-button class="btn-spacing"
|
||||
color="accent">
|
||||
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
|
||||
</button>
|
||||
|
||||
<button *ngIf="movieRequest && !movieRequest.denied" mat-raised-button class="btn-spacing" color="warn"
|
||||
(click)="deny()">
|
||||
<i class="fas fa-times"></i> {{
|
||||
'Requests.Deny' | translate }}</button>
|
||||
<button *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason"
|
||||
mat-raised-button class="btn-spacing" color="warn">
|
||||
<i class="fas fa-times"></i> {{
|
||||
'MediaDetails.Denied' | translate }}</button>
|
||||
</span> -->
|
||||
|
||||
<!-- <button *ngIf="(hasRequest && movieRequest) || movie.available" mat-raised-button class="btn-spacing"
|
||||
color="danger" (click)="issue()">
|
||||
<i class="fas fa-exclamation"></i> {{
|
||||
'Requests.ReportIssue' | translate }}</button> -->
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<!-- <div class="col-12 col-md-2">
|
||||
|
||||
<mat-card class="mat-elevation-z8">
|
||||
<mat-card-content class="medium-font">
|
||||
<album-information-panel [album]="album"></album-information-panel>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
|
||||
</div> -->
|
||||
|
||||
<div class="col-12 col-md-10">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<mat-card class=" mat-elevation-z8 spacing-below">
|
||||
<mat-card-content>
|
||||
<h1>{{album.title}} - {{album.disambiguation}}</h1>
|
||||
<br />
|
||||
{{album.overview}}
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="row">
|
||||
<div class="col-12">
|
||||
<div class="issuesPanel" *ngIf="album.requestId">
|
||||
<issues-panel [requestId]="album.requestId" [isAdmin]="isAdmin"></issues-panel>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- <div class="row">
|
||||
<div class="col-12">
|
||||
<mat-accordion class="mat-elevation-z8 spacing-below">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{'MediaDetails.RecommendationsTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.recommendations.results.length > 0">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of movie.recommendations.results">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster">
|
||||
<a [routerLink]="'/details/movie/'+r.id">
|
||||
<img class="real grow" matTooltip="{{r.title}}"
|
||||
src="https://image.tmdb.org/t/p/w300/{{r.poster_path}}" alt="Poster"
|
||||
style="display: block;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{'MediaDetails.SimilarTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.similar.results.length > 0">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of movie.similar.results">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster ">
|
||||
<a [routerLink]="'/details/movie/'+r.id">
|
||||
<img class="real grow" matTooltip="{{r.title}}"
|
||||
src="https://image.tmdb.org/t/p/w300/{{r.poster_path}}" alt="Poster"
|
||||
style="display: block;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{'MediaDetails.VideosTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.videos.results.length > 0">
|
||||
|
||||
<div class="col-md-6" *ngFor="let video of movie.videos.results">
|
||||
<iframe width="100%" height="315px" [src]="'https://www.youtube.com/embed/' + video.key | safe"
|
||||
frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="bottom-page-gap">
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
|
@ -0,0 +1,126 @@
|
|||
import { Component, ViewEncapsulation } from "@angular/core";
|
||||
import { ImageService, SearchV2Service, RequestService, MessageService } from "../../../services";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { YoutubeTrailerComponent } from "../shared/youtube-trailer.component";
|
||||
import { AuthService } from "../../../auth/auth.service";
|
||||
import { DenyDialogComponent } from "../shared/deny-dialog/deny-dialog.component";
|
||||
import { NewIssueComponent } from "../shared/new-issue/new-issue.component";
|
||||
import { IAlbumSearchResult, IReleaseGroups } from "../../../interfaces/IMusicSearchResultV2";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./album-details.component.html",
|
||||
styleUrls: ["../../media-details.component.scss"],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class AlbumDetailsComponent {
|
||||
private albumId: string;
|
||||
|
||||
public album: IAlbumSearchResult = null;
|
||||
private selectedAlbums: IReleaseGroups[] = [];
|
||||
|
||||
public isAdmin: boolean;
|
||||
|
||||
constructor(private searchService: SearchV2Service, private route: ActivatedRoute,
|
||||
private sanitizer: DomSanitizer, private imageService: ImageService,
|
||||
public dialog: MatDialog, private requestService: RequestService,
|
||||
public messageService: MessageService, private auth: AuthService) {
|
||||
this.route.params.subscribe((params: any) => {
|
||||
this.albumId = params.albumId;
|
||||
this.load();
|
||||
});
|
||||
}
|
||||
|
||||
public load() {
|
||||
this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");
|
||||
this.searchService.getAlbumInformation(this.albumId).subscribe(x => this.album = x);
|
||||
}
|
||||
|
||||
public getBackground(): string {
|
||||
if (this.album.cover) {
|
||||
this.album.background = this.sanitizer.bypassSecurityTrustStyle
|
||||
("url(" + this.album.cover + ")");
|
||||
return this.album.background
|
||||
}
|
||||
|
||||
return this.album.background
|
||||
}
|
||||
|
||||
public async requestAlbum() {
|
||||
if (this.album.monitored) {
|
||||
return;
|
||||
}
|
||||
this.requestService.requestAlbum({
|
||||
foreignAlbumId: this.album.id,
|
||||
monitored: true,
|
||||
monitor: "existing",
|
||||
searchForMissingAlbums: true
|
||||
}).toPromise()
|
||||
.then(r => {
|
||||
if (r.result) {
|
||||
this.album.monitored = true;
|
||||
this.messageService.send(r.message);
|
||||
} else {
|
||||
this.messageService.send(r.errorMessage);
|
||||
}
|
||||
})
|
||||
.catch(r => {
|
||||
console.log(r);
|
||||
this.messageService.send("Error when requesting album");
|
||||
});
|
||||
// const
|
||||
}
|
||||
|
||||
public openDialog() {
|
||||
this.dialog.open(YoutubeTrailerComponent, {
|
||||
width: '560px',
|
||||
// data: this.movie.videos.results[0].key
|
||||
});
|
||||
}
|
||||
|
||||
public async deny() {
|
||||
const dialogRef = this.dialog.open(DenyDialogComponent, {
|
||||
width: '250px',
|
||||
// data: {requestId: this.movieRequest.id, requestType: RequestType.movie}
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
// this.movieRequest.denied = result;
|
||||
// if(this.movieRequest.denied) {
|
||||
// this.movie.approved = false;
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
public async issue() {
|
||||
const dialogRef = this.dialog.open(NewIssueComponent, {
|
||||
width: '500px',
|
||||
// data: {requestId: this.movieRequest ? this.movieRequest.id : null, requestType: RequestType.movie, imdbid: this.movie.imdbId}
|
||||
});
|
||||
}
|
||||
|
||||
public async approve() {
|
||||
// const result = await this.requestService.approveMovie({ id: this.movieRequest.id }).toPromise();
|
||||
// if (result.result) {
|
||||
// this.movie.approved = false;
|
||||
// this.messageService.send("Successfully Approved", "Ok");
|
||||
// } else {
|
||||
// this.messageService.send(result.errorMessage, "Ok");
|
||||
// }
|
||||
}
|
||||
|
||||
public async markAvailable() {
|
||||
// const result = await this.requestService.markMovieAvailable({id: this.movieRequest.id}).toPromise();
|
||||
// if (result.result) {
|
||||
// // this.movie.available = true;
|
||||
// this.messageService.send(result.message, "Ok");
|
||||
// } else {
|
||||
// this.messageService.send(result.errorMessage, "Ok");
|
||||
// }
|
||||
}
|
||||
|
||||
public setAdvancedOptions(data: any) {
|
||||
// this.advancedOptions = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<div *ngIf="album">
|
||||
<div>
|
||||
<strong>Type:</strong>
|
||||
<div>{{album.type}}</div>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Country</strong>
|
||||
<div>{{album.country}}</div>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Release Date</strong>
|
||||
<div>{{album.startYear}}</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,12 @@
|
|||
import { Component, Input, ViewEncapsulation } from "@angular/core";
|
||||
import { ISearchArtistResult } from "../../../../../interfaces";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./album-information-panel.component.html",
|
||||
styleUrls: ["../../../../media-details.component.scss"],
|
||||
selector: "album-information-panel",
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class AlbumInformationPanel {
|
||||
@Input() public album: ISearchAlbumResult;
|
||||
}
|
|
@ -16,73 +16,22 @@
|
|||
<!--Next to poster-->
|
||||
<div class="col-12 col-lg-3 col-xl-3 media-row">
|
||||
|
||||
<social-icons [homepage]="artist.links.homePage" [doNotAppend]="true" [imdbId]="artist.links.imdb" [twitter]="artist.links.twitter" [facebook]="artist.links.facebook" [instagram]="artist.links.instagram"></social-icons>
|
||||
<!-- <social-icons [homepage]="artist.links.homePage" [doNotAppend]="true" [imdbId]="artist.links.imdb" [twitter]="artist.links.twitter" [facebook]="artist.links.facebook" [instagram]="artist.links.instagram"></social-icons> -->
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-lg-6 col-xl-6 media-row">
|
||||
|
||||
<button mat-raised-button *ngIf="selectedAlbums.length === 0" class="btn-spacing" color="primary" (click)="requestAllAlbums()">
|
||||
<i class="fas fa-plus"></i> {{ 'MediaDetails.RequestAllAlbums' | translate }}</button>
|
||||
<button mat-raised-button *ngIf="selectedAlbums.length > 0" class="btn-spacing" color="primary" (click)="requestAllAlbums()">
|
||||
<i class="fas fa-plus"></i> {{ 'MediaDetails.RequestSelectedAlbums' | translate }}</button>
|
||||
|
||||
<button mat-raised-button *ngIf="selectedAlbums.length > 0" class="btn-spacing" color="accent" (click)="clearSelection()">
|
||||
<i class="fas fa-minus"></i> {{ 'MediaDetails.ClearSelection' | translate }}</button>
|
||||
|
||||
|
||||
|
||||
<!-- <button mat-raised-button class="btn-green btn-spacing" *ngIf="movie.available"> {{
|
||||
'Common.Available' | translate }}</button> -->
|
||||
<!-- <span *ngIf="!movie.available">
|
||||
<span *ngIf="movie.requested || movie.approved; then requestedBtn else notRequestedBtn"></span>
|
||||
|
||||
<ng-template #requestedBtn>
|
||||
<button mat-raised-button *ngIf="!hasRequest || hasRequest && movieRequest && !movieRequest.denied"
|
||||
class="btn-spacing" color="warn" [disabled]><i class="fas fa-check"></i>
|
||||
{{ 'Common.Requested' | translate }}</button>
|
||||
</ng-template>
|
||||
<ng-template #notRequestedBtn>
|
||||
<button mat-raised-button class="btn-spacing" color="primary" (click)="request()">
|
||||
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i> <i
|
||||
*ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
|
||||
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i> {{
|
||||
'Common.Request' | translate }}</button>
|
||||
</ng-template>
|
||||
</span> -->
|
||||
<!-- <span *ngIf="isAdmin && hasRequest">
|
||||
<button (click)="approve()" mat-raised-button class="btn-spacing" color="accent">
|
||||
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
|
||||
</button>
|
||||
<button *ngIf="!movie.available" (click)="markAvailable()" mat-raised-button class="btn-spacing"
|
||||
color="accent">
|
||||
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
|
||||
</button>
|
||||
|
||||
<button *ngIf="movieRequest && !movieRequest.denied" mat-raised-button class="btn-spacing" color="warn"
|
||||
(click)="deny()">
|
||||
<i class="fas fa-times"></i> {{
|
||||
'Requests.Deny' | translate }}</button>
|
||||
<button *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason"
|
||||
mat-raised-button class="btn-spacing" color="warn">
|
||||
<i class="fas fa-times"></i> {{
|
||||
'MediaDetails.Denied' | translate }}</button>
|
||||
</span> -->
|
||||
|
||||
<!-- <button *ngIf="(hasRequest && movieRequest) || movie.available" mat-raised-button class="btn-spacing"
|
||||
color="danger" (click)="issue()">
|
||||
<i class="fas fa-exclamation"></i> {{
|
||||
'Requests.ReportIssue' | translate }}</button> -->
|
||||
|
||||
|
||||
|
||||
|
||||
<button mat-raised-button *ngIf="artist.monitored" class="btn-spacing" color="primary"
|
||||
color="accent" [disabled]>
|
||||
<i class="fa-lg fas fa-check"></i> {{'Common.Monitored' | translate }}</button>
|
||||
<button mat-raised-button *ngIf="!artist.monitored && selectedAlbums.length === 0" class="btn-spacing" color="primary" (click)="requestAllAlbums()">
|
||||
<i class="fas fa-plus"></i> {{ 'Common.Request' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12 col-md-2">
|
||||
<!-- <div class="col-12 col-md-2">
|
||||
|
||||
<mat-card class="mat-elevation-z8">
|
||||
<mat-card-content class="medium-font">
|
||||
|
@ -91,7 +40,7 @@
|
|||
</mat-card>
|
||||
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div class="col-12 col-md-10">
|
||||
<div class="row">
|
||||
|
@ -106,7 +55,7 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<artist-release-panel (onAlbumSelect)="albumSelected($event)" (albumLoad)="albumLoad($event)" *ngIf="artist.releaseGroups.length > 0" [releases]="artist.releaseGroups"></artist-release-panel>
|
||||
<artist-release-panel (onAlbumSelect)="albumSelected($event)" (albumLoad)="albumLoad($event)" *ngIf="artist.releaseGroups?.length > 0" [releases]="artist.releaseGroups"></artist-release-panel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -119,78 +68,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="row">
|
||||
<div class="col-12">
|
||||
<mat-accordion class="mat-elevation-z8 spacing-below">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{'MediaDetails.RecommendationsTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.recommendations.results.length > 0">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of movie.recommendations.results">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster">
|
||||
<a [routerLink]="'/details/movie/'+r.id">
|
||||
<img class="real grow" matTooltip="{{r.title}}"
|
||||
src="https://image.tmdb.org/t/p/w300/{{r.poster_path}}" alt="Poster"
|
||||
style="display: block;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{'MediaDetails.SimilarTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.similar.results.length > 0">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of movie.similar.results">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster ">
|
||||
<a [routerLink]="'/details/movie/'+r.id">
|
||||
<img class="real grow" matTooltip="{{r.title}}"
|
||||
src="https://image.tmdb.org/t/p/w300/{{r.poster_path}}" alt="Poster"
|
||||
style="display: block;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{'MediaDetails.VideosTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer" *ngIf="movie.videos.results.length > 0">
|
||||
|
||||
<div class="col-md-6" *ngFor="let video of movie.videos.results">
|
||||
<iframe width="100%" height="315px" [src]="'https://www.youtube.com/embed/' + video.key | safe"
|
||||
frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component } from "@angular/core";
|
||||
import { Component, ViewEncapsulation } from "@angular/core";
|
||||
import { ImageService, SearchV2Service, RequestService, MessageService } from "../../../services";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
|
@ -12,6 +12,7 @@ import { IArtistSearchResult, IReleaseGroups } from "../../../interfaces/IMusicS
|
|||
@Component({
|
||||
templateUrl: "./artist-details.component.html",
|
||||
styleUrls: ["../../media-details.component.scss"],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ArtistDetailsComponent {
|
||||
private artistId: string;
|
||||
|
@ -87,7 +88,10 @@ export class ArtistDetailsComponent {
|
|||
return;
|
||||
}
|
||||
this.requestService.requestAlbum({
|
||||
foreignAlbumId : a.id
|
||||
foreignAlbumId : a.id,
|
||||
monitored: true,
|
||||
monitor: "all",
|
||||
searchForMissingAlbums: true
|
||||
}).toPromise()
|
||||
.then(r => {
|
||||
if (r.result) {
|
||||
|
@ -110,7 +114,10 @@ export class ArtistDetailsComponent {
|
|||
return;
|
||||
}
|
||||
this.requestService.requestAlbum({
|
||||
foreignAlbumId : a.id
|
||||
foreignAlbumId : a.id,
|
||||
monitored: true,
|
||||
monitor: "all",
|
||||
searchForMissingAlbums: true
|
||||
}).toPromise()
|
||||
.then(r => {
|
||||
if (r.result) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import { MovieAdvancedOptionsComponent } from "./movie/panels/movie-advanced-opt
|
|||
import { SearchService, RequestService, RadarrService, IssuesService, SonarrService } from "../../services";
|
||||
import { RequestServiceV2 } from "../../services/requestV2.service";
|
||||
import { NewIssueComponent } from "./shared/new-issue/new-issue.component";
|
||||
import { AlbumDetailsComponent } from "./album/album-details.component";
|
||||
import { ArtistDetailsComponent } from "./artist/artist-details.component";
|
||||
import { ArtistInformationPanel } from "./artist/panels/artist-information-panel/artist-information-panel.component";
|
||||
import { ArtistReleasePanel } from "./artist/panels/artist-release-panel/artist-release-panel.component";
|
||||
|
@ -37,6 +38,7 @@ export const components: any[] = [
|
|||
MovieAdvancedOptionsComponent,
|
||||
TvAdvancedOptionsComponent,
|
||||
NewIssueComponent,
|
||||
AlbumDetailsComponent,
|
||||
ArtistDetailsComponent,
|
||||
ArtistInformationPanel,
|
||||
ArtistReleasePanel,
|
||||
|
|
|
@ -25,7 +25,7 @@ export class DenyDialogComponent {
|
|||
if(this.data.requestType == RequestType.tvShow) {
|
||||
result = await this.requestService.denyChild({id: this.data.requestId, reason: this.denyReason }).toPromise();
|
||||
}
|
||||
if(this.data.requestType == RequestType.album) {
|
||||
if(this.data.requestType == RequestType.artist) {
|
||||
result = await this.requestService.denyAlbum({id: this.data.requestId, reason: this.denyReason }).toPromise();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="sidebar sidebar-poster affixable affix-top">
|
||||
<div class="poster mobile-poster">
|
||||
<img class="real" src="{{posterPath}}" alt="Poster"
|
||||
style="display: block;">
|
||||
style="display: block; max-width: 400px;">
|
||||
</div>
|
||||
<!--Underneith poster-->
|
||||
<br />
|
||||
|
|
|
@ -95,6 +95,10 @@
|
|||
line-height: 1.2;
|
||||
}
|
||||
|
||||
#summary-wrapper .row {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
#info-wrapper {
|
||||
min-height: 600px;
|
||||
}
|
||||
|
@ -256,10 +260,6 @@
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
#info-wrapper{
|
||||
margin-top:-200px;
|
||||
}
|
||||
.full-screenshot.enabled.overlay{
|
||||
background-image: linear-gradient(to bottom, transparent, 50%, $ombi-background-primary);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import { PipeModule } from "../pipes/pipe.module";
|
|||
import * as fromComponents from './components';
|
||||
import { AuthGuard } from "../auth/auth.guard";
|
||||
import { ArtistDetailsComponent } from "./components/artist/artist-details.component";
|
||||
import { AlbumDetailsComponent } from "./components/album/album-details.component";
|
||||
import { ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
|
||||
|
@ -19,6 +20,7 @@ const routes: Routes = [
|
|||
{ path: "tv/:tvdbId/:search", component: TvDetailsComponent, canActivate: [AuthGuard] },
|
||||
{ path: "tv/:tvdbId", component: TvDetailsComponent, canActivate: [AuthGuard] },
|
||||
{ path: "artist/:artistId", component: ArtistDetailsComponent, canActivate: [AuthGuard] },
|
||||
{ path: "album/:albumId", component: AlbumDetailsComponent, canActivate: [AuthGuard] },
|
||||
];
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
|
|
@ -22,7 +22,7 @@ export class RequestOptionsComponent {
|
|||
if (this.data.type === RequestType.tvShow) {
|
||||
await this.requestService.deleteChild(this.data.id).toPromise();
|
||||
}
|
||||
if (this.data.type === RequestType.album) {
|
||||
if (this.data.type === RequestType.artist) {
|
||||
await this.requestService.removeAlbumRequest(this.data.id).toPromise();
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ export class RequestOptionsComponent {
|
|||
if (this.data.type === RequestType.tvShow) {
|
||||
await this.requestService.approveChild({id: this.data.id}).toPromise();
|
||||
}
|
||||
if (this.data.type === RequestType.album) {
|
||||
if (this.data.type === RequestType.artist) {
|
||||
await this.requestService.approveAlbum({id: this.data.id}).toPromise();
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ export class RequestOptionsComponent {
|
|||
if (this.data.type === RequestType.movie) {
|
||||
await this.requestService.markMovieAvailable({id: this.data.id}).toPromise();
|
||||
}
|
||||
if (this.data.type === RequestType.album) {
|
||||
if (this.data.type === RequestType.artist) {
|
||||
await this.requestService.markAlbumAvailable({id: this.data.id}).toPromise();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ import { HttpClient } from "@angular/common/http";
|
|||
import { Observable } from "rxjs";
|
||||
|
||||
import { UITreeNode } from "primeng/tree";
|
||||
import { FilterType, IAlbumRequest, IAlbumRequestModel, IAlbumUpdateModel, IChildRequests, IDenyAlbumModel, IDenyMovieModel, IFilter,
|
||||
import {
|
||||
FilterType, IAlbumRequest, IAlbumRequestModel, IArtistRequestModel, IAlbumUpdateModel, IChildRequests, IDenyAlbumModel, IDenyMovieModel, IFilter,
|
||||
IMovieRequestModel, IMovieRequests, IMovieUpdateModel, IRequestEngineResult, IRequestsViewModel, ITvDenyModel, ITvRequests, ITvUpdateModel, OrderType } from "../interfaces";
|
||||
import { ServiceHelpers } from "./service.helpers";
|
||||
|
||||
|
@ -153,7 +154,10 @@ export class RequestService extends ServiceHelpers {
|
|||
|
||||
// Music
|
||||
public requestAlbum(Album: IAlbumRequestModel): Observable<IRequestEngineResult> {
|
||||
return this.http.post<IRequestEngineResult>(`${this.url}music/`, JSON.stringify(Album), {headers: this.headers});
|
||||
return this.http.post<IRequestEngineResult>(`${this.url}album/`, JSON.stringify(Album), {headers: this.headers});
|
||||
}
|
||||
public requestArtist(Artist: IArtistRequestModel): Observable<IRequestEngineResult> {
|
||||
return this.http.post<IRequestEngineResult>(`${this.url}artist/`, JSON.stringify(Artist), { headers: this.headers });
|
||||
}
|
||||
|
||||
public getTotalAlbums(): Observable<number> {
|
||||
|
|
|
@ -9,7 +9,7 @@ import { ServiceHelpers } from "./service.helpers";
|
|||
|
||||
import { ISearchMovieResultV2 } from "../interfaces/ISearchMovieResultV2";
|
||||
import { ISearchTvResultV2, IMovieCollectionsViewModel, IActorCredits } from "../interfaces/ISearchTvResultV2";
|
||||
import { IArtistSearchResult, IAlbumArt, IReleaseGroups } from "../interfaces/IMusicSearchResultV2";
|
||||
import { IArtistSearchResult, IAlbumSearchResult, IAlbumArt, IReleaseGroups } from "../interfaces/IMusicSearchResultV2";
|
||||
import { SearchFilter } from "../my-nav/SearchFilter";
|
||||
import { IMovieRatings, ITvRatings } from "../interfaces/IRatings";
|
||||
import { IStreamingData } from "../interfaces/IStreams";
|
||||
|
@ -136,6 +136,10 @@ export class SearchV2Service extends ServiceHelpers {
|
|||
return this.http.get<IArtistSearchResult>(`${this.url}/artist/${artistId}`);
|
||||
}
|
||||
|
||||
public getAlbumInformation(albumId: string): Observable<IAlbumSearchResult> {
|
||||
return this.http.get<IAlbumSearchResult>(`${this.url}/artist/album/${albumId}`);
|
||||
}
|
||||
|
||||
public getReleaseGroupArt(mbid: string): Observable<IAlbumArt> {
|
||||
return this.http.get<IAlbumArt>(`${this.url}/releasegroupart/${mbid}`);
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ export class RemainingRequestsComponent implements OnInit {
|
|||
this.matIcon = "fas fa-tv";
|
||||
|
||||
break;
|
||||
case RequestType.album:
|
||||
case RequestType.artist:
|
||||
this.requestService.getRemainingMusicRequests().subscribe(callback);
|
||||
this.matIcon = "fas fa-music";
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
"no-internal-module": false,
|
||||
"quotemark": [ true, "double", "avoid-template" ],
|
||||
"no-console": false,
|
||||
"no-non-null-assertion": false,
|
||||
"no-non-null-assertion": false
|
||||
},
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators":true,
|
||||
"experimentalDecorators":false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ using ILogger = Microsoft.Extensions.Logging.ILogger;
|
|||
namespace Ombi.Controllers.V1
|
||||
{
|
||||
[Authorize]
|
||||
[Route("api/v1/request/music")]
|
||||
[Route("api/v1/request")]
|
||||
[Produces("application/json")]
|
||||
[ApiController]
|
||||
public class MusicRequestController : ControllerBase
|
||||
|
@ -42,7 +42,7 @@ namespace Ombi.Controllers.V1
|
|||
/// <param name="statusType"></param>
|
||||
/// <param name="availabilityType"></param>
|
||||
[HttpGet("{count:int}/{position:int}/{orderType:int}/{statusType:int}/{availabilityType:int}")]
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetRequests(int count, int position, int orderType, int statusType, int availabilityType)
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetRequests(int count, int position, int orderType, int statusType, int availabilityType)
|
||||
{
|
||||
return await _engine.GetRequests(count, position, new OrderFilterModel
|
||||
{
|
||||
|
@ -65,7 +65,7 @@ namespace Ombi.Controllers.V1
|
|||
/// Gets all album requests.
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<AlbumRequest>> GetRequests()
|
||||
public async Task<IEnumerable<MusicRequests>> GetRequests()
|
||||
{
|
||||
return await _engine.GetRequests();
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ namespace Ombi.Controllers.V1
|
|||
/// </summary>
|
||||
/// <param name="album">The album.</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[HttpPost("album")]
|
||||
public async Task<RequestEngineResult> RequestAlbum([FromBody] MusicAlbumRequestViewModel album)
|
||||
{
|
||||
album.RequestedByAlias = GetApiAlias();
|
||||
|
@ -92,13 +92,36 @@ namespace Ombi.Controllers.V1
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requests a artist.
|
||||
/// </summary>
|
||||
/// <param name="artist">The artist.</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("artist")]
|
||||
public async Task<RequestEngineResult> RequestArtist([FromBody] MusicArtistRequestViewModel artist)
|
||||
{
|
||||
Console.Write(artist);
|
||||
artist.RequestedByAlias = GetApiAlias();
|
||||
var result = await _engine.RequestArtist(artist);
|
||||
if (result.Result)
|
||||
{
|
||||
var voteResult = await _voteEngine.UpVote(result.RequestId, RequestType.Artist);
|
||||
if (voteResult.IsError)
|
||||
{
|
||||
_log.LogError("Couldn't automatically add the vote for the artist {0} because {1}", artist.ForeignArtistId, voteResult.ErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a specific album request
|
||||
/// </summary>
|
||||
/// <param name="searchTerm">The search term.</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("search/{searchTerm}")]
|
||||
public async Task<IEnumerable<AlbumRequest>> Search(string searchTerm)
|
||||
public async Task<IEnumerable<MusicRequests>> Search(string searchTerm)
|
||||
{
|
||||
return await _engine.SearchAlbumRequest(searchTerm);
|
||||
}
|
||||
|
|
|
@ -151,31 +151,31 @@ namespace Ombi.Controllers.V2
|
|||
}
|
||||
|
||||
[HttpGet("album/available/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetAvailableAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetAvailableAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
{
|
||||
return await _musicRequestEngine.GetRequestsByStatus(count, position, sort, sortOrder, RequestStatus.Available);
|
||||
}
|
||||
|
||||
[HttpGet("album/processing/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetProcessingAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetProcessingAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
{
|
||||
return await _musicRequestEngine.GetRequestsByStatus(count, position, sort, sortOrder, RequestStatus.ProcessingRequest);
|
||||
}
|
||||
|
||||
[HttpGet("album/pending/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetPendingAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetPendingAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
{
|
||||
return await _musicRequestEngine.GetRequestsByStatus(count, position, sort, sortOrder, RequestStatus.PendingApproval);
|
||||
}
|
||||
|
||||
[HttpGet("album/denied/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetDeniedAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetDeniedAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
{
|
||||
return await _musicRequestEngine.GetRequestsByStatus(count, position, sort, sortOrder, RequestStatus.Denied);
|
||||
}
|
||||
|
||||
[HttpGet("album/{count:int}/{position:int}/{sort}/{sortOrder}")]
|
||||
public async Task<RequestsViewModel<AlbumRequest>> GetAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
public async Task<RequestsViewModel<MusicRequests>> GetAlbumRequests(int count, int position, string sort, string sortOrder)
|
||||
{
|
||||
return await _musicRequestEngine.GetRequests(count, position, sort, sortOrder);
|
||||
}
|
||||
|
|
|
@ -416,9 +416,9 @@ namespace Ombi.Controllers.V2
|
|||
[HttpGet("artist/album/{albumId}")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesDefaultResponseType]
|
||||
public Task<ReleaseGroup> GetAlbumInformation(string albumId)
|
||||
public Task<AlbumInformation> GetAlbumInformation(string albumId)
|
||||
{
|
||||
return _musicEngine.GetAlbum(albumId);
|
||||
return _musicEngine.GetAlbumInformation(albumId);
|
||||
}
|
||||
|
||||
[HttpGet("releasegroupart/{musicBrainzId}")]
|
||||
|
|
|
@ -34,7 +34,9 @@
|
|||
"Cancel": "Cancel",
|
||||
"Submit": "Submit",
|
||||
"tvShow": "TV Show",
|
||||
"movie": "Movie"
|
||||
"movie": "Movie",
|
||||
"album": "Album",
|
||||
"artist": "Artist"
|
||||
},
|
||||
"PasswordReset": {
|
||||
"EmailAddressPlaceholder": "Email Address",
|
||||
|
@ -253,6 +255,7 @@
|
|||
"RequestAllAlbums": "Request All Albums",
|
||||
"ClearSelection": "Clear Selection",
|
||||
"RequestSelectedAlbums": "Request Selected Albums",
|
||||
"RequestAlbum": "Request Album",
|
||||
"ViewCollection":"View Collection",
|
||||
"NotEnoughInfo": "Unfortunately there is not enough information about this show yet!",
|
||||
"AdvancedOptions":"Advanced Options",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue