mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-03-12 04:35:27 -07:00
More work on music!
This commit is contained in:
parent
98346d1c86
commit
12a80c7903
src
Ombi.Api.MusicBrainz
Ombi.Api
Ombi.Core
Ombi
ClientApp/src/app
interfaces
media-details/components/artist/panels/artist-release-panel
services
settings/lidarr
Controllers/V2
wwwroot/translations
@ -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<IEnumerable<Artist>> SearchArtist(string artistQuery);
|
||||
Task<IEnumerable<Release>> GetReleaseForArtist(string artistId);
|
||||
Task<Artist> GetArtistInformation(string artistId);
|
||||
Task<ReleaseGroupArt> GetCoverArtForReleaseGroup(string musicBrainzId, CancellationToken token);
|
||||
}
|
||||
}
|
37
src/Ombi.Api.MusicBrainz/Models/ReleaseGroupArt.cs
Normal file
37
src/Ombi.Api.MusicBrainz/Models/ReleaseGroupArt.cs
Normal file
@ -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; }
|
||||
}
|
||||
|
||||
}
|
@ -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<IEnumerable<Artist>> 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<ReleaseGroupArt> 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<ReleaseGroupArt>(jsonContent, Api.Settings);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void AddHeaders(Request req)
|
||||
{
|
||||
req.AddHeader("Accept", "application/json");
|
||||
|
@ -25,7 +25,7 @@ namespace Ombi.Api
|
||||
private ILogger<Api> 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<HttpResponseMessage> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<HttpResponseMessage> Request(Request request, CancellationToken token = default(CancellationToken));
|
||||
Task<T> Request<T>(Request request, CancellationToken cancellationToken = default(CancellationToken));
|
||||
Task<string> RequestContent(Request request);
|
||||
T DeserializeXml<T>(string receivedString);
|
||||
|
@ -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<ArtistInformation> GetArtistInformation(string artistId);
|
||||
Task<AlbumArt> GetReleaseGroupArt(string musicBrainzId, CancellationToken token);
|
||||
}
|
||||
}
|
@ -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<AlbumArt> 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<BandMember> GetBandMembers(Artist artist)
|
||||
{
|
||||
var members = new List<BandMember>();
|
||||
|
16
src/Ombi.Core/Models/Search/V2/Music/AlbumArt.cs
Normal file
16
src/Ombi.Core/Models/Search/V2/Music/AlbumArt.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,71 +1,28 @@
|
||||
<mat-accordion class="mat-elevation-z8 spacing-below">
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
|
||||
|
||||
|
||||
<mat-card class="example-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>
|
||||
{{'MediaDetails.AlbumsTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<div class="row card-spacer">
|
||||
|
||||
<div class="row card-spacer">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of albums">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster">
|
||||
<!-- <img class="real grow" matTooltip="{{r.title}}"
|
||||
src="{{r.title}}" alt="Poster"
|
||||
style="display: block;"> -->
|
||||
{{r.title}} | {{r.type}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel *ngIf="ep">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{'MediaDetails.SinglesTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of singles">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster">
|
||||
<!-- <img class="real grow" matTooltip="{{r.title}}"
|
||||
src="{{r.title}}" alt="Poster"
|
||||
style="display: block;"> -->
|
||||
{{r.title}} | {{r.type}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span *ngFor="let r of albums">
|
||||
<div class="col-md-2" *ngIf="r.image" >
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster">
|
||||
<img class="real grow" matTooltip="{{r.title}}"
|
||||
src="{{r.image}}" alt="Poster"
|
||||
style="display: block;">
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
{{'MediaDetails.EpTitle' | translate}}
|
||||
</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<div class="row card-spacer">
|
||||
|
||||
<div class="col-md-2" *ngFor="let r of ep">
|
||||
<div class="sidebar affixable affix-top preview-poster">
|
||||
<div class="poster">
|
||||
<!-- <img class="real grow" matTooltip="{{r.title}}"
|
||||
src="{{r.title}}" alt="Poster"
|
||||
style="display: block;"> -->
|
||||
{{r.title}} | {{r.type}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
|
||||
</mat-accordion>
|
||||
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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<IArtistSearchResult> {
|
||||
return this.http.get<IArtistSearchResult>(`${this.url}/artist/${artistId}`);
|
||||
}
|
||||
|
||||
public getReleaseGroupArt(mbid: string): Observable<IAlbumArt> {
|
||||
return this.http.get<IAlbumArt>(`${this.url}/releasegroupart/${mbid}`);
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<div><button mat-raised-button (click)="getLanguaggetMetadataProfileseProfiles(form)" color="primary">Load Metadata <span
|
||||
<div><button mat-raised-button (click)="getMetadataProfiles(form)" color="primary">Load Metadata <span
|
||||
*ngIf="metadataRunning" class="fa fa-spinner fa-spin"></span></button></div>
|
||||
</div>
|
||||
|
||||
|
@ -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<AlbumArt> GetReleaseGroupARt(string musicBrainzId)
|
||||
{
|
||||
return await _musicEngine.GetReleaseGroupArt(musicBrainzId, CancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -203,6 +203,7 @@
|
||||
"RecommendationsTitle": "Recommendations",
|
||||
"SimilarTitle": "Similar",
|
||||
"VideosTitle": "Videos",
|
||||
"AlbumsTitle":"Albums",
|
||||
"Casts": {
|
||||
"CastTitle": "Cast",
|
||||
"Character": "Character",
|
||||
|
Loading…
x
Reference in New Issue
Block a user