diff --git a/src/Ombi.Api.MusicBrainz/IMusicBrainzApi.cs b/src/Ombi.Api.MusicBrainz/IMusicBrainzApi.cs index 951f690b7..69d8231ad 100644 --- a/src/Ombi.Api.MusicBrainz/IMusicBrainzApi.cs +++ b/src/Ombi.Api.MusicBrainz/IMusicBrainzApi.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Hqub.MusicBrainz.API.Entities; +using Ombi.Api.MusicBrainz.Models; namespace Ombi.Api.MusicBrainz { @@ -9,5 +11,6 @@ namespace Ombi.Api.MusicBrainz Task> SearchArtist(string artistQuery); Task> GetReleaseForArtist(string artistId); Task GetArtistInformation(string artistId); + Task GetCoverArtForReleaseGroup(string musicBrainzId, CancellationToken token); } } \ No newline at end of file diff --git a/src/Ombi.Api.MusicBrainz/Models/ReleaseGroupArt.cs b/src/Ombi.Api.MusicBrainz/Models/ReleaseGroupArt.cs new file mode 100644 index 000000000..bccd8bd5a --- /dev/null +++ b/src/Ombi.Api.MusicBrainz/Models/ReleaseGroupArt.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; + +namespace Ombi.Api.MusicBrainz.Models +{ + + public class ReleaseGroupArt + { + public string release { get; set; } + public Image[] images { get; set; } + } + + public class Image + { + public int edit { get; set; } + public string id { get; set; } + public string image { get; set; } + public Thumbnails thumbnails { get; set; } + public string comment { get; set; } + public bool approved { get; set; } + public bool front { get; set; } + public string[] types { get; set; } + public bool back { get; set; } + } + + public class Thumbnails + { + //[JsonProperty("250")] + //public string px250 { get; set; } + //[JsonProperty("500")] + //public string px500 { get; set; } + //[JsonProperty("1200")] + //public string px1200 { get; set; } + public string small { get; set; } + public string large { get; set; } + } + +} \ No newline at end of file diff --git a/src/Ombi.Api.MusicBrainz/MusicBrainzApi.cs b/src/Ombi.Api.MusicBrainz/MusicBrainzApi.cs index f096b0073..3c86d7882 100644 --- a/src/Ombi.Api.MusicBrainz/MusicBrainzApi.cs +++ b/src/Ombi.Api.MusicBrainz/MusicBrainzApi.cs @@ -2,14 +2,24 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Hqub.MusicBrainz.API; using Hqub.MusicBrainz.API.Entities; +using Newtonsoft.Json; +using Ombi.Api.MusicBrainz.Models; namespace Ombi.Api.MusicBrainz { public class MusicBrainzApi : IMusicBrainzApi { + private readonly IApi _api; + + public MusicBrainzApi(IApi api) + { + _api = api; + } + public async Task> SearchArtist(string artistQuery) { var artist = await Artist.SearchAsync(artistQuery, 10); @@ -34,10 +44,21 @@ namespace Ombi.Api.MusicBrainz // Search for a release by title. var releases = await Release.SearchAsync(query); - return releases.Items; } + public async Task GetCoverArtForReleaseGroup(string musicBrainzId, CancellationToken token) + { + var request = new Request($"release-group/{musicBrainzId}", "http://coverartarchive.org", HttpMethod.Get); + var result = await _api.Request(request, token); + if (result.IsSuccessStatusCode) + { + var jsonContent = await result.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(jsonContent, Api.Settings); + } + return null; + } + private void AddHeaders(Request req) { req.AddHeader("Accept", "application/json"); diff --git a/src/Ombi.Api/Api.cs b/src/Ombi.Api/Api.cs index 3f9928c33..764da5a13 100644 --- a/src/Ombi.Api/Api.cs +++ b/src/Ombi.Api/Api.cs @@ -25,7 +25,7 @@ namespace Ombi.Api private ILogger Logger { get; } private readonly IOmbiHttpClient _client; - private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings + public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, ContractResolver = new PluralPropertyContractResolver() @@ -66,7 +66,7 @@ namespace Ombi.Api { using (var req = await httpRequestMessage.Clone()) { - return await _client.SendAsync(req); + return await _client.SendAsync(req, cancellationToken); } }); } @@ -119,12 +119,12 @@ namespace Ombi.Api } - public async Task Request(Request request) + public async Task Request(Request request, CancellationToken token = default(CancellationToken)) { using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri)) { AddHeadersBody(request, httpRequestMessage); - var httpResponseMessage = await _client.SendAsync(httpRequestMessage); + var httpResponseMessage = await _client.SendAsync(httpRequestMessage, token); await LogDebugContent(httpResponseMessage); if (!httpResponseMessage.IsSuccessStatusCode) { @@ -133,6 +133,8 @@ namespace Ombi.Api await LogError(request, httpResponseMessage); } } + + return httpResponseMessage; } } diff --git a/src/Ombi.Api/IApi.cs b/src/Ombi.Api/IApi.cs index f1daf0257..fa5f77ee5 100644 --- a/src/Ombi.Api/IApi.cs +++ b/src/Ombi.Api/IApi.cs @@ -1,11 +1,12 @@ -using System.Threading; +using System.Net.Http; +using System.Threading; using System.Threading.Tasks; namespace Ombi.Api { public interface IApi { - Task Request(Request request); + Task Request(Request request, CancellationToken token = default(CancellationToken)); Task Request(Request request, CancellationToken cancellationToken = default(CancellationToken)); Task RequestContent(Request request); T DeserializeXml(string receivedString); diff --git a/src/Ombi.Core/Engine/Interfaces/IMusicSearchEngineV2.cs b/src/Ombi.Core/Engine/Interfaces/IMusicSearchEngineV2.cs index 73c45347e..f318290d8 100644 --- a/src/Ombi.Core/Engine/Interfaces/IMusicSearchEngineV2.cs +++ b/src/Ombi.Core/Engine/Interfaces/IMusicSearchEngineV2.cs @@ -1,3 +1,4 @@ +using System.Threading; using System.Threading.Tasks; using Ombi.Core.Models.Search.V2.Music; @@ -6,5 +7,6 @@ namespace Ombi.Core.Engine.Interfaces public interface IMusicSearchEngineV2 { Task GetArtistInformation(string artistId); + Task GetReleaseGroupArt(string musicBrainzId, CancellationToken token); } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/V2/MusicSearchEngineV2.cs b/src/Ombi.Core/Engine/V2/MusicSearchEngineV2.cs index 07a2f0ef6..1ba26d764 100644 --- a/src/Ombi.Core/Engine/V2/MusicSearchEngineV2.cs +++ b/src/Ombi.Core/Engine/V2/MusicSearchEngineV2.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Principal; +using System.Threading; using System.Threading.Tasks; using Ombi.Api.Lidarr; using Ombi.Api.Lidarr.Models; @@ -81,7 +82,7 @@ namespace Ombi.Core.Engine.V2 if (lidarrArtistTask != null) { var artistResult = await lidarrArtistTask; - info.Banner = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("banner", StringComparison.InvariantCultureIgnoreCase))?.url.Replace("http","https"); + info.Banner = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("banner", StringComparison.InvariantCultureIgnoreCase))?.url.Replace("http", "https"); info.Logo = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("logo", StringComparison.InvariantCultureIgnoreCase))?.url.Replace("http", "https"); info.Poster = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("poster", StringComparison.InvariantCultureIgnoreCase))?.url.Replace("http", "https"); info.FanArt = artistResult.images?.FirstOrDefault(x => x.coverType.Equals("fanart", StringComparison.InvariantCultureIgnoreCase))?.url.Replace("http", "https"); @@ -90,7 +91,39 @@ namespace Ombi.Core.Engine.V2 return info; } - + + public async Task GetReleaseGroupArt(string musicBrainzId, CancellationToken token) + { + var art = await _musicBrainzApi.GetCoverArtForReleaseGroup(musicBrainzId, token); + + if (art == null || !art.images.Any()) + { + return new AlbumArt(); + } + + foreach (var cover in art.images) + { + //if ((cover.thumbnails?.px250 ?? string.Empty).HasValue()) + //{ + // return new AlbumArt(cover.thumbnails.px250); + //} + if ((cover.thumbnails?.small ?? string.Empty).HasValue()) + { + return new AlbumArt(cover.thumbnails.small); + } + //if ((cover.thumbnails?.px500 ?? string.Empty).HasValue()) + //{ + // return new AlbumArt(cover.thumbnails.px500); + //} + if ((cover.thumbnails?.large ?? string.Empty).HasValue()) + { + return new AlbumArt(cover.thumbnails.large); + } + } + + return new AlbumArt(); + } + private List GetBandMembers(Artist artist) { var members = new List(); diff --git a/src/Ombi.Core/Models/Search/V2/Music/AlbumArt.cs b/src/Ombi.Core/Models/Search/V2/Music/AlbumArt.cs new file mode 100644 index 000000000..a49c8e19f --- /dev/null +++ b/src/Ombi.Core/Models/Search/V2/Music/AlbumArt.cs @@ -0,0 +1,16 @@ +namespace Ombi.Core.Models.Search.V2.Music +{ + public class AlbumArt + { + public AlbumArt() + { + + } + + public AlbumArt(string url) + { + Image = url; + } + public string Image { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/interfaces/IMusicSearchResultV2.ts b/src/Ombi/ClientApp/src/app/interfaces/IMusicSearchResultV2.ts index 9c87d3250..cf141fea7 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/IMusicSearchResultV2.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/IMusicSearchResultV2.ts @@ -24,6 +24,8 @@ export interface IReleaseGroups { title: string; releaseDate: string; type: string; + + image: string; // Set by another api call } export interface IArtistLinks { @@ -53,4 +55,8 @@ export interface IBandMembers { isCurrentMember: boolean; start: string; end: string; +} + +export interface IAlbumArt { + image: string; } \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/media-details/components/artist/panels/artist-release-panel/artist-release-panel.component.html b/src/Ombi/ClientApp/src/app/media-details/components/artist/panels/artist-release-panel/artist-release-panel.component.html index 8d001b736..86143b4c5 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/artist/panels/artist-release-panel/artist-release-panel.component.html +++ b/src/Ombi/ClientApp/src/app/media-details/components/artist/panels/artist-release-panel/artist-release-panel.component.html @@ -1,71 +1,28 @@ - - - - - {{'MediaDetails.AlbumsTitle' | translate}} - - - -
-
- -
-
-
- - - - - {{'MediaDetails.SinglesTitle' | translate}} - - - -
- -
- + + + + {{'MediaDetails.AlbumsTitle' | translate}} + + + + +
+ + +
+ - - - - - - {{'MediaDetails.EpTitle' | translate}} - - - -
- -
- - -
-
-
- - \ No newline at end of file + +
+
+
+
+
\ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/media-details/components/artist/panels/artist-release-panel/artist-release-panel.component.ts b/src/Ombi/ClientApp/src/app/media-details/components/artist/panels/artist-release-panel/artist-release-panel.component.ts index 9d637802d..662957ef8 100644 --- a/src/Ombi/ClientApp/src/app/media-details/components/artist/panels/artist-release-panel/artist-release-panel.component.ts +++ b/src/Ombi/ClientApp/src/app/media-details/components/artist/panels/artist-release-panel/artist-release-panel.component.ts @@ -1,5 +1,6 @@ import { Component, Input, ViewEncapsulation, OnInit } from "@angular/core"; import { IReleaseGroups } from "../../../../../interfaces/IMusicSearchResultV2"; +import { SearchV2Service } from "../../../../../services/searchV2.service"; @Component({ templateUrl: "./artist-release-panel.component.html", @@ -12,12 +13,14 @@ export class ArtistReleasePanel implements OnInit { @Input() public releases: IReleaseGroups[]; public albums: IReleaseGroups[]; - public singles: IReleaseGroups[]; - public ep: IReleaseGroups[]; - public ngOnInit(): void { + constructor(private searchService: SearchV2Service) { } + + public ngOnInit() { this.albums = this.releases.filter(x => x.type === "Album"); - this.singles = this.releases.filter(x => x.type === "Single"); - this.ep = this.releases.filter(x => x.type === "EP"); + + this.albums.forEach(a => { + this.searchService.getReleaseGroupArt(a.id).subscribe(x => a.image = x.image); + }); } } diff --git a/src/Ombi/ClientApp/src/app/services/searchV2.service.ts b/src/Ombi/ClientApp/src/app/services/searchV2.service.ts index b25f74755..59dd71917 100644 --- a/src/Ombi/ClientApp/src/app/services/searchV2.service.ts +++ b/src/Ombi/ClientApp/src/app/services/searchV2.service.ts @@ -9,7 +9,7 @@ import { ServiceHelpers } from "./service.helpers"; import { ISearchMovieResultV2 } from "../interfaces/ISearchMovieResultV2"; import { ISearchTvResultV2, IMovieCollectionsViewModel, IActorCredits } from "../interfaces/ISearchTvResultV2"; -import { IArtistSearchResult } from "../interfaces/IMusicSearchResultV2"; +import { IArtistSearchResult, IAlbumArt } from "../interfaces/IMusicSearchResultV2"; @Injectable() export class SearchV2Service extends ServiceHelpers { @@ -103,4 +103,8 @@ export class SearchV2Service extends ServiceHelpers { public getArtistInformation(artistId: string): Observable { return this.http.get(`${this.url}/artist/${artistId}`); } + + public getReleaseGroupArt(mbid: string): Observable { + return this.http.get(`${this.url}/releasegroupart/${mbid}`); + } } diff --git a/src/Ombi/ClientApp/src/app/settings/lidarr/lidarr.component.html b/src/Ombi/ClientApp/src/app/settings/lidarr/lidarr.component.html index 6824214d7..2db0d4414 100644 --- a/src/Ombi/ClientApp/src/app/settings/lidarr/lidarr.component.html +++ b/src/Ombi/ClientApp/src/app/settings/lidarr/lidarr.component.html @@ -94,7 +94,7 @@ -
diff --git a/src/Ombi/Controllers/V2/SearchController.cs b/src/Ombi/Controllers/V2/SearchController.cs index 9476299b4..1e2f9776c 100644 --- a/src/Ombi/Controllers/V2/SearchController.cs +++ b/src/Ombi/Controllers/V2/SearchController.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using System.Threading.Tasks; using System.Collections.Generic; +using System.Threading; using Ombi.Core; using Ombi.Api.TheMovieDb.Models; using Ombi.Core.Engine.V2; @@ -343,5 +344,12 @@ namespace Ombi.Controllers.V2 return await _musicEngine.GetArtistInformation(artistId); } + [HttpGet("releasegroupart/{musicBrainzId}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesDefaultResponseType] + public async Task GetReleaseGroupARt(string musicBrainzId) + { + return await _musicEngine.GetReleaseGroupArt(musicBrainzId, CancellationToken); + } } } \ No newline at end of file diff --git a/src/Ombi/Controllers/V2/V2Controller.cs b/src/Ombi/Controllers/V2/V2Controller.cs index 0165512d1..faf0a1cae 100644 --- a/src/Ombi/Controllers/V2/V2Controller.cs +++ b/src/Ombi/Controllers/V2/V2Controller.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Authorization; +using System.Threading; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Ombi.Controllers.V2 @@ -9,6 +10,6 @@ namespace Ombi.Controllers.V2 [ApiController] public class V2Controller : ControllerBase { - + public CancellationToken CancellationToken => HttpContext.RequestAborted; } } \ No newline at end of file diff --git a/src/Ombi/wwwroot/translations/en.json b/src/Ombi/wwwroot/translations/en.json index 95546dfc6..5bf986d8d 100644 --- a/src/Ombi/wwwroot/translations/en.json +++ b/src/Ombi/wwwroot/translations/en.json @@ -203,6 +203,7 @@ "RecommendationsTitle": "Recommendations", "SimilarTitle": "Similar", "VideosTitle": "Videos", + "AlbumsTitle":"Albums", "Casts": { "CastTitle": "Cast", "Character": "Character",