From 615edc80927107e429487882ac82605711e6c3d2 Mon Sep 17 00:00:00 2001 From: Niels van Velzen Date: Tue, 2 Jan 2024 19:52:08 +0100 Subject: [PATCH] Somewhat working now --- ...emplate.sln => Jellyfin.Plugin.Discogs.sln | 0 Jellyfin.Plugin.Discogs/DiscogsApi.cs | 61 +++++++++++++++++++ .../Jellyfin.Plugin.Discogs.csproj | 1 - .../PluginServiceRegistrator.cs | 9 +-- .../Providers/DiscogsArtistProvider.cs | 53 ++++++---------- 5 files changed, 80 insertions(+), 44 deletions(-) rename Jellyfin.Plugin.Template.sln => Jellyfin.Plugin.Discogs.sln (100%) create mode 100644 Jellyfin.Plugin.Discogs/DiscogsApi.cs diff --git a/Jellyfin.Plugin.Template.sln b/Jellyfin.Plugin.Discogs.sln similarity index 100% rename from Jellyfin.Plugin.Template.sln rename to Jellyfin.Plugin.Discogs.sln diff --git a/Jellyfin.Plugin.Discogs/DiscogsApi.cs b/Jellyfin.Plugin.Discogs/DiscogsApi.cs new file mode 100644 index 0000000..3cfcdb7 --- /dev/null +++ b/Jellyfin.Plugin.Discogs/DiscogsApi.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Text.Json.Nodes; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using Jellyfin.Plugin.Discogs.Configuration; +using MediaBrowser.Common.Net; +using Microsoft.AspNetCore.WebUtilities; + +namespace Jellyfin.Plugin.Discogs; + +#pragma warning disable CS1591 +public class DiscogsApi +{ + private const string Server = "https://api.discogs.com/"; + private readonly HttpClient _client; + + public DiscogsApi(IHttpClientFactory clientFactory) : this(clientFactory, Plugin.Instance!.Configuration) + { + } + + public DiscogsApi(IHttpClientFactory clientFactory, PluginConfiguration configuration) + { + _client = clientFactory.CreateClient(NamedClient.Default); + + // TODO: This doesn't update the token when configuration changes + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Discogs", $"token={configuration.ApiToken}"); + } + + public async Task GetArtist(string id, CancellationToken cancellationToken) + { + var uri = new Uri($"{Server}artists/{HttpUtility.UrlEncode(id)}"); + var response = await _client.GetAsync(uri, cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + } + + public async Task Search(string query, string? type, CancellationToken cancellationToken) + { + var uri = new Uri(QueryHelpers.AddQueryString($"{Server}database/search", new Dictionary { { "q", query }, { "type", type } })); + var response = await _client.GetAsync(uri, cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + return await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + } + + public async Task GetImage(string url, CancellationToken cancellationToken) + { + if (!url.StartsWith(Server, StringComparison.Ordinal)) + { + throw new ArgumentException($"URL does not start with {Server}", nameof(url)); + } + + var response = await _client.GetAsync(url, cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + return response; + } +} diff --git a/Jellyfin.Plugin.Discogs/Jellyfin.Plugin.Discogs.csproj b/Jellyfin.Plugin.Discogs/Jellyfin.Plugin.Discogs.csproj index 1982e1a..c0ea009 100644 --- a/Jellyfin.Plugin.Discogs/Jellyfin.Plugin.Discogs.csproj +++ b/Jellyfin.Plugin.Discogs/Jellyfin.Plugin.Discogs.csproj @@ -11,7 +11,6 @@ - diff --git a/Jellyfin.Plugin.Discogs/PluginServiceRegistrator.cs b/Jellyfin.Plugin.Discogs/PluginServiceRegistrator.cs index e7af207..74ed990 100644 --- a/Jellyfin.Plugin.Discogs/PluginServiceRegistrator.cs +++ b/Jellyfin.Plugin.Discogs/PluginServiceRegistrator.cs @@ -1,5 +1,4 @@ -using DiscogsApiClient; -using MediaBrowser.Common.Plugins; +using MediaBrowser.Common.Plugins; using Microsoft.Extensions.DependencyInjection; namespace Jellyfin.Plugin.Discogs; @@ -10,10 +9,6 @@ public class PluginServiceRegistrator : IPluginServiceRegistrator /// public void RegisterServices(IServiceCollection serviceCollection) { - serviceCollection.AddDiscogsApiClient(options => - { - // TODO: Add jellyfin & plugin version - options.UserAgent = "Jellyfin/1.0.0"; - }); + serviceCollection.AddSingleton(); } } diff --git a/Jellyfin.Plugin.Discogs/Providers/DiscogsArtistProvider.cs b/Jellyfin.Plugin.Discogs/Providers/DiscogsArtistProvider.cs index 504b413..d92cacf 100644 --- a/Jellyfin.Plugin.Discogs/Providers/DiscogsArtistProvider.cs +++ b/Jellyfin.Plugin.Discogs/Providers/DiscogsArtistProvider.cs @@ -1,15 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Globalization; +using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using DiscogsApiClient; -using DiscogsApiClient.Authentication; -using DiscogsApiClient.QueryParameters; -using Jellyfin.Extensions; -using Jellyfin.Plugin.Discogs.Configuration; using Jellyfin.Plugin.Discogs.ExternalIds; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; @@ -23,21 +16,15 @@ namespace Jellyfin.Plugin.Discogs.Providers; /// public class DiscogsArtistProvider : IRemoteMetadataProvider { - private readonly IDiscogsApiClient _discogsApiClient; - private readonly IDiscogsAuthenticationService _discogsAuthenticationService; - private readonly PluginConfiguration _configuration; + private readonly DiscogsApi _api; /// /// Initializes a new instance of the class. /// - /// The discogsApiClient. - /// The discogsAuthenticationService. - /// The configuration. - public DiscogsArtistProvider(IDiscogsApiClient discogsApiClient, IDiscogsAuthenticationService discogsAuthenticationService, PluginConfiguration configuration) + /// The Discogs API. + public DiscogsArtistProvider(DiscogsApi api) { - _discogsApiClient = discogsApiClient; - _discogsAuthenticationService = discogsAuthenticationService; - _configuration = configuration; + _api = api; } /// @@ -46,18 +33,16 @@ public class DiscogsArtistProvider : IRemoteMetadataProvider public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) { - _discogsAuthenticationService.AuthenticateWithPersonalAccessToken(_configuration.ApiToken); - var artistId = searchInfo.GetProviderId(DiscogsArtistExternalId.ProviderKey); - if (artistId != null && int.TryParse(artistId, out var artistIdInt)) + if (artistId != null) { - var result = await _discogsApiClient.GetArtist(artistIdInt, cancellationToken).ConfigureAwait(false); - return new[] { new RemoteSearchResult { ProviderIds = new Dictionary { { DiscogsArtistExternalId.ProviderKey, result.Id.ToString(CultureInfo.InvariantCulture) }, }, Name = result.Name, ImageUrl = result.Images.FirstOrDefault()?.ImageUri150 } }; + var result = await _api.GetArtist(artistId, cancellationToken).ConfigureAwait(false); + return new[] { new RemoteSearchResult { ProviderIds = new Dictionary { { DiscogsArtistExternalId.ProviderKey, result!["id"]!.ToString() }, }, Name = result!["name"]!.ToString(), ImageUrl = result!["images"]!.AsArray().FirstOrDefault()?["uri150"]?.ToString() } }; } else { - var response = await _discogsApiClient.SearchDatabase(new SearchQueryParameters { Query = searchInfo.Name, Type = "artist", }, cancellationToken: cancellationToken).ConfigureAwait(false); - return response.Results.Select(result => new RemoteSearchResult { ProviderIds = new Dictionary { { DiscogsArtistExternalId.ProviderKey, result.Id.ToString(CultureInfo.InvariantCulture) }, }, Name = result.Title, ImageUrl = result.CoverImageUrl, }); + var response = await _api.Search(searchInfo.Name, "artist", cancellationToken).ConfigureAwait(false); + return response!["results"]!.AsArray().Select(result => new RemoteSearchResult { ProviderIds = new Dictionary { { DiscogsArtistExternalId.ProviderKey, result!["id"]!.ToString() }, }, Name = result["title"]!.ToString(), ImageUrl = result!["cover_image_url"]?.ToString(), }); } } @@ -65,17 +50,16 @@ public class DiscogsArtistProvider : IRemoteMetadataProvider> GetMetadata(ArtistInfo info, CancellationToken cancellationToken) { var artistId = info.GetProviderId(DiscogsArtistExternalId.ProviderKey); - if (artistId != null && int.TryParse(artistId, out var artistIdInt)) + if (artistId != null) { - _discogsAuthenticationService.AuthenticateWithPersonalAccessToken(_configuration.ApiToken); - var result = await _discogsApiClient.GetArtist(artistIdInt, cancellationToken).ConfigureAwait(false); + var result = await _api.GetArtist(artistId, cancellationToken).ConfigureAwait(false); return new MetadataResult { - Item = new MusicArtist { ProviderIds = new Dictionary() { { DiscogsArtistExternalId.ProviderKey, result.Id.ToString(CultureInfo.InvariantCulture) }, }, Name = result.Name, Overview = result.Profile, }, - RemoteImages = result.Images - .Where(image => image.Type == DiscogsApiClient.Contract.ImageType.Primary) - .Select(image => (image.ImageUri, ImageType.Primary)) + Item = new MusicArtist { ProviderIds = new Dictionary { { DiscogsArtistExternalId.ProviderKey, result!["id"]!.ToString() } }, Name = result!["name"]!.ToString(), Overview = result!["profile"]!.ToString(), }, + RemoteImages = result!["images"]!.AsArray() + .Where(image => image!["type"]!.ToString() == "primary") + .Select(image => (image!["uri"]!.ToString(), ImageType.Primary)) .ToList(), QueriedById = true, HasMetadata = true, @@ -86,8 +70,5 @@ public class DiscogsArtistProvider : IRemoteMetadataProvider - public Task GetImageResponse(string url, CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } + public Task GetImageResponse(string url, CancellationToken cancellationToken) => _api.GetImage(url, cancellationToken); }