diff --git a/Jellyfin.Plugin.Vgmdb.csproj b/Jellyfin.Plugin.Vgmdb.csproj deleted file mode 100644 index f78d0c8..0000000 --- a/Jellyfin.Plugin.Vgmdb.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - net5.0 - 1.2.0.0 - - - - - - - - diff --git a/Jellyfin.Plugin.Vgmdb.sln b/Jellyfin.Plugin.Vgmdb.sln new file mode 100644 index 0000000..7b974c5 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Plugin.Vgmdb", "Jellyfin.Plugin.Vgmdb\Jellyfin.Plugin.Vgmdb.csproj", "{AEE55B5F-1B35-4155-AFBF-D7586DC39F04}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AEE55B5F-1B35-4155-AFBF-D7586DC39F04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEE55B5F-1B35-4155-AFBF-D7586DC39F04}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEE55B5F-1B35-4155-AFBF-D7586DC39F04}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEE55B5F-1B35-4155-AFBF-D7586DC39F04}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/Jellyfin.Plugin.Vgmdb/ExternalIds/VgmdbAlbumExternalId.cs b/Jellyfin.Plugin.Vgmdb/ExternalIds/VgmdbAlbumExternalId.cs new file mode 100644 index 0000000..e4c7cde --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/ExternalIds/VgmdbAlbumExternalId.cs @@ -0,0 +1,23 @@ +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; + +namespace Jellyfin.Plugin.Vgmdb.ExternalIds; + +/// +// ReSharper disable once ClassNeverInstantiated.Global +public class VgmdbAlbumExternalId : IExternalId +{ + public const string ExternalId = "VGMdbAlbum"; + + public string ProviderName => "VGMdb Album"; + + public string Key => ExternalId; + + public ExternalIdMediaType? Type => ExternalIdMediaType.Album; + + public string UrlFormatString => "https://vgmdb.net/album/{0}"; + + public bool Supports(IHasProviderIds item) => item is MusicAlbum; +} diff --git a/Jellyfin.Plugin.Vgmdb/ExternalIds/VgmdbArtistExternalId.cs b/Jellyfin.Plugin.Vgmdb/ExternalIds/VgmdbArtistExternalId.cs new file mode 100644 index 0000000..2798d25 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/ExternalIds/VgmdbArtistExternalId.cs @@ -0,0 +1,23 @@ +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; + +namespace Jellyfin.Plugin.Vgmdb.ExternalIds; + +/// +// ReSharper disable once ClassNeverInstantiated.Global +public class VgmdbArtistExternalId : IExternalId +{ + public const string ExternalId = "VGMdbArtist"; + + public string ProviderName => "VGMdb Artist"; + + public string Key => ExternalId; + + public ExternalIdMediaType? Type => ExternalIdMediaType.Album; + + public string UrlFormatString => "https://vgmdb.net/artist/{0}"; + + public bool Supports(IHasProviderIds item) => item is MusicArtist; +} diff --git a/Jellyfin.Plugin.Vgmdb/Jellyfin.Plugin.Vgmdb.csproj b/Jellyfin.Plugin.Vgmdb/Jellyfin.Plugin.Vgmdb.csproj new file mode 100644 index 0000000..9a138f5 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Jellyfin.Plugin.Vgmdb.csproj @@ -0,0 +1,20 @@ + + + net6.0 + 1.0.0.0 + false + false + disable + AllEnabledByDefault + ../jellyfin.ruleset + + + + + + + + + + + diff --git a/Jellyfin.Plugin.Vgmdb/Models/AlbumResponse.cs b/Jellyfin.Plugin.Vgmdb/Models/AlbumResponse.cs new file mode 100644 index 0000000..c22ff2d --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Models/AlbumResponse.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.Vgmdb.Models; + +public class AlbumResponse +{ + [JsonPropertyName("names")] + public LocalizedString Names { get; set; } + + [JsonPropertyName("picture_full")] + public string PictureFull { get; set; } + + [JsonPropertyName("picture_small")] + public string PictureSmall { get; set; } + + [JsonPropertyName("picture_thumb")] + public string PictureThumb { get; set; } + + [JsonPropertyName("link")] + public string Link { get; set; } + + [JsonPropertyName("notes")] + public string Notes { get; set; } + + [JsonPropertyName("release_date")] + public string ReleaseDate { get; set; } + + [JsonPropertyName("categories")] + public IReadOnlyList Categories { get; set; } = Array.Empty(); + + [JsonPropertyName("organizations")] + public IReadOnlyList Organizations { get; set; } = Array.Empty(); + + public int Id => int.Parse(Link.Replace("album/", string.Empty, StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture); +} diff --git a/Jellyfin.Plugin.Vgmdb/Models/ArtistResponse.cs b/Jellyfin.Plugin.Vgmdb/Models/ArtistResponse.cs new file mode 100644 index 0000000..6e130df --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Models/ArtistResponse.cs @@ -0,0 +1,25 @@ +using System; +using System.Globalization; +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.Vgmdb.Models; + +public class ArtistResponse +{ + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("picture_full")] + public string PictureFull { get; set; } + + [JsonPropertyName("picture_small")] + public string PictureSmall { get; set; } + + [JsonPropertyName("link")] + public string Link { get; set; } + + [JsonPropertyName("notes")] + public string Notes { get; set; } + + public int Id => int.Parse(Link.Replace("artist/", string.Empty, StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture); +} diff --git a/Jellyfin.Plugin.Vgmdb/Models/LocalizedString.cs b/Jellyfin.Plugin.Vgmdb/Models/LocalizedString.cs new file mode 100644 index 0000000..d7107ab --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Models/LocalizedString.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.Vgmdb.Models; + +public class LocalizedString +{ + [JsonPropertyName("en")] + public string En { get; set; } + + [JsonPropertyName("ja")] + public string Ja { get; set; } + + [JsonPropertyName("jaLatn")] + public string JaLatn { get; set; } + + public string GetPreferred() + { + return JaLatn ?? En ?? Ja; + } +} diff --git a/Jellyfin.Plugin.Vgmdb/Models/Organization.cs b/Jellyfin.Plugin.Vgmdb/Models/Organization.cs new file mode 100644 index 0000000..28f9b77 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Models/Organization.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.Vgmdb.Models; + +public class Organization +{ + [JsonPropertyName("link")] + public string Link { get; set; } + + [JsonPropertyName("names")] + public LocalizedString Names { get; set; } + + [JsonPropertyName("role")] + public string Role { get; set; } + + public int Id => int.Parse(Link.Replace("org/", string.Empty, StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture); +} diff --git a/Jellyfin.Plugin.Vgmdb/Models/SearchResponse.cs b/Jellyfin.Plugin.Vgmdb/Models/SearchResponse.cs new file mode 100644 index 0000000..f439ac4 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Models/SearchResponse.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.Vgmdb.Models; + +public class SearchResponse +{ + [JsonPropertyName("results")] + public SearchResponseResults Results { get; set; } +} diff --git a/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResults.cs b/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResults.cs new file mode 100644 index 0000000..6a936cf --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResults.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.Vgmdb.Models; + +public class SearchResponseResults +{ + [JsonPropertyName("albums")] + public IReadOnlyList Albums { get; set; } = Array.Empty(); + + [JsonPropertyName("artists")] + public IReadOnlyList Artists { get; set; } = Array.Empty(); +} diff --git a/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResultsAlbum.cs b/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResultsAlbum.cs new file mode 100644 index 0000000..36ead58 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResultsAlbum.cs @@ -0,0 +1,22 @@ +using System; +using System.Globalization; +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.Vgmdb.Models; + +public class SearchResponseResultsAlbum +{ + [JsonPropertyName("catalog")] + public string Catalog { get; set; } + + [JsonPropertyName("link")] + public string Link { get; set; } + + [JsonPropertyName("release_date")] + public string ReleaseDate { get; set; } + + [JsonPropertyName("titles")] + public LocalizedString Titles { get; set; } + + public int Id => int.Parse(Link.Replace("album/", string.Empty, StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture); +} diff --git a/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResultsArtist.cs b/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResultsArtist.cs new file mode 100644 index 0000000..3cfd4d3 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Models/SearchResponseResultsArtist.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.Json.Serialization; + +namespace Jellyfin.Plugin.Vgmdb.Models; + +public class SearchResponseResultsArtist +{ + [JsonPropertyName("aliases")] + public IReadOnlyList Aliases { get; set; } = Array.Empty(); + + [JsonPropertyName("link")] + public string Link { get; set; } + + [JsonPropertyName("names")] + public LocalizedString Names { get; set; } + + public int Id => int.Parse(Link.Replace("artist/", string.Empty, StringComparison.OrdinalIgnoreCase), CultureInfo.InvariantCulture); +} diff --git a/Jellyfin.Plugin.Vgmdb/PluginConfiguration.cs b/Jellyfin.Plugin.Vgmdb/PluginConfiguration.cs new file mode 100644 index 0000000..03186ba --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/PluginConfiguration.cs @@ -0,0 +1,8 @@ +using MediaBrowser.Model.Plugins; + +namespace Jellyfin.Plugin.Vgmdb; + +/// +public class PluginConfiguration : BasePluginConfiguration +{ +} diff --git a/Jellyfin.Plugin.Vgmdb/Providers/Images/VgmdbAlbumImageProvider.cs b/Jellyfin.Plugin.Vgmdb/Providers/Images/VgmdbAlbumImageProvider.cs new file mode 100644 index 0000000..61abee7 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Providers/Images/VgmdbAlbumImageProvider.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Plugin.Vgmdb.ExternalIds; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; + +namespace Jellyfin.Plugin.Vgmdb.Providers.Images; + +public class VgmdbAlbumImageProvider : IRemoteImageProvider +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly VgmdbApi _api; + + public VgmdbAlbumImageProvider(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + _api = new VgmdbApi(httpClientFactory); + } + + public string Name => "VGMdb"; + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken); + } + + public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) + { + var images = new List(); + + var id = item.GetProviderId(VgmdbAlbumExternalId.ExternalId); + + // todo use a search to find id + if (id == null) + { + return images; + } + + var album = await _api.GetAlbumById(int.Parse(id, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false); + + images.Add(new RemoteImageInfo + { + Url = album.PictureFull, + ThumbnailUrl = album.PictureSmall + }); + + return images; + } + + public IEnumerable GetSupportedImages(BaseItem item) + { + return new List + { + ImageType.Primary + }; + } + + public bool Supports(BaseItem item) => item is MusicAlbum; +} diff --git a/Jellyfin.Plugin.Vgmdb/Providers/Images/VgmdbArtistImageProvider.cs b/Jellyfin.Plugin.Vgmdb/Providers/Images/VgmdbArtistImageProvider.cs new file mode 100644 index 0000000..48a490c --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Providers/Images/VgmdbArtistImageProvider.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Plugin.Vgmdb.ExternalIds; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; + +namespace Jellyfin.Plugin.Vgmdb.Providers.Images; + +public class VgmdbArtistImageProvider : IRemoteImageProvider +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly VgmdbApi _api; + + public VgmdbArtistImageProvider(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + _api = new VgmdbApi(httpClientFactory); + } + + public string Name => "VGMdb"; + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken); + } + + public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) + { + var images = new List(); + + var id = item.GetProviderId(VgmdbArtistExternalId.ExternalId); + + // todo use a search to find id + if (id == null) + { + return images; + } + + var artist = await _api.GetArtistByIdAsync(int.Parse(id, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false); + + images.Add(new RemoteImageInfo + { + Url = artist.PictureFull, + ThumbnailUrl = artist.PictureSmall + }); + + return images; + } + + public IEnumerable GetSupportedImages(BaseItem item) + { + return new List + { + ImageType.Primary + }; + } + + public bool Supports(BaseItem item) => item is MusicArtist; +} diff --git a/Jellyfin.Plugin.Vgmdb/Providers/Info/VgmdbAlbumProvider.cs b/Jellyfin.Plugin.Vgmdb/Providers/Info/VgmdbAlbumProvider.cs new file mode 100644 index 0000000..eb69439 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Providers/Info/VgmdbAlbumProvider.cs @@ -0,0 +1,151 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Plugin.Vgmdb.ExternalIds; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; + +namespace Jellyfin.Plugin.Vgmdb.Providers.Info; + +public class VgmdbAlbumProvider : IRemoteMetadataProvider +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly VgmdbApi _api; + + public VgmdbAlbumProvider(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + _api = new VgmdbApi(httpClientFactory); + } + + public string Name => "VGMdb"; + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken); + } + + public async Task GetAlbumByIdAsync(int id, CancellationToken cancellationToken) + { + var response = await _api.GetAlbumById(id, cancellationToken).ConfigureAwait(false); + + if (response == null) + { + return null; + } + + var album = new MusicAlbum + { + ProviderIds = + { + [VgmdbAlbumExternalId.ExternalId] = response.Id.ToString(CultureInfo.InvariantCulture) + }, + Name = response.Names.GetPreferred() + }; + + // todo better date parsing + _ = int.TryParse(response.ReleaseDate.Split('-')[0], out var productionYear); + if (productionYear > 0) + { + album.ProductionYear = productionYear; + } + + var image = new ItemImageInfo + { + Path = response.PictureFull, + Type = ImageType.Primary + }; + album.SetImage(image, 0); + + album.Overview = response.Notes; + + if (response.Categories != null) + { + foreach (var category in response.Categories) + { + album.AddGenre(category); + } + } + + if (response.Organizations != null) + { + foreach (var organisation in response.Organizations) + { + album.AddStudio(organisation.Names.GetPreferred()); + } + } + + return album; + } + + public async Task GetIdAsync(AlbumInfo info, CancellationToken cancellationToken) + { + var providedId = info.GetProviderId(VgmdbAlbumExternalId.ExternalId); + if (providedId != null) + { + return int.Parse(providedId, CultureInfo.InvariantCulture); + } + + var searchResults = await GetSearchResults(info, cancellationToken).ConfigureAwait(false); + + foreach (var result in searchResults) + { + var id = result.GetProviderId(VgmdbAlbumExternalId.ExternalId); + + if (id != null) + { + return int.Parse(id, CultureInfo.InvariantCulture); + } + } + + return null; + } + + public async Task> GetMetadata(AlbumInfo info, CancellationToken cancellationToken) + { + var id = await GetIdAsync(info, cancellationToken).ConfigureAwait(false); + + if (id != null) + { + return new MetadataResult + { + Item = await GetAlbumByIdAsync(id.Value, cancellationToken).ConfigureAwait(false) + }; + } + + return new MetadataResult(); + } + + public async Task> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken) + { + var response = await _api.GetSearchResultsAsync(searchInfo.Name, cancellationToken).ConfigureAwait(false); + + var searchResults = new List(); + if (response == null) + { + return null; + } + + foreach (var albumEntry in response.Results.Albums) + { + var album = await GetAlbumByIdAsync(albumEntry.Id, cancellationToken).ConfigureAwait(false); + var result = new RemoteSearchResult + { + ProviderIds = album.ProviderIds, + Name = album.Name, + ProductionYear = album.ProductionYear, + ImageUrl = album.PrimaryImagePath + }; + + searchResults.Add(result); + } + + return searchResults; + } +} diff --git a/Jellyfin.Plugin.Vgmdb/Providers/Info/VgmdbArtistProvider.cs b/Jellyfin.Plugin.Vgmdb/Providers/Info/VgmdbArtistProvider.cs new file mode 100644 index 0000000..23d36ad --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/Providers/Info/VgmdbArtistProvider.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Plugin.Vgmdb.ExternalIds; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; + +namespace Jellyfin.Plugin.Vgmdb.Providers.Info; + +public class VgmdbArtistProvider : IRemoteMetadataProvider +{ + private readonly IHttpClientFactory _httpClientFactory; + private readonly VgmdbApi _api; + + public VgmdbArtistProvider(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + _api = new VgmdbApi(httpClientFactory); + } + + public string Name => "VGMdb"; + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken); + } + + public async Task GetArtistByIdAsync(int id, CancellationToken cancellationToken) + { + var response = await _api.GetArtistByIdAsync(id, cancellationToken).ConfigureAwait(false); + + if (response == null) + { + return null; + } + + var artist = new MusicArtist + { + ProviderIds = + { + [VgmdbArtistExternalId.ExternalId] = response.Id.ToString(CultureInfo.InvariantCulture) + }, + Name = response.Name + }; + + var image = new ItemImageInfo + { + Path = response.PictureFull, + Type = ImageType.Primary + }; + artist.SetImage(image, 0); + + artist.Overview = response.Notes; + + return artist; + } + + public async Task GetIdAsync(ArtistInfo info, CancellationToken cancellationToken) + { + var providedId = info.GetProviderId(VgmdbArtistExternalId.ExternalId); + if (providedId != null) + { + return int.Parse(providedId, CultureInfo.InvariantCulture); + } + + var searchResults = await GetSearchResults(info, cancellationToken).ConfigureAwait(false); + + foreach (var result in searchResults) + { + var id = result.GetProviderId(VgmdbArtistExternalId.ExternalId); + + if (id != null) + { + return int.Parse(id, CultureInfo.InvariantCulture); + } + } + + return null; + } + + public async Task> GetMetadata(ArtistInfo info, CancellationToken cancellationToken) + { + var id = await GetIdAsync(info, cancellationToken).ConfigureAwait(false); + + if (id != null) + { + return new MetadataResult + { + Item = await GetArtistByIdAsync(id.Value, cancellationToken).ConfigureAwait(false) + }; + } + + return new MetadataResult(); + } + + public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) + { + var response = await _api.GetSearchResultsAsync(searchInfo.Name, cancellationToken).ConfigureAwait(false); + if (response == null) + { + return null; + } + + var searchResults = new List(); + + foreach (var artistEntry in response.Results.Artists) + { + var artist = await GetArtistByIdAsync(artistEntry.Id, cancellationToken).ConfigureAwait(false); + var result = new RemoteSearchResult + { + ProviderIds = artist.ProviderIds, + Name = artist.Name, + ImageUrl = artist.PrimaryImagePath + }; + + searchResults.Add(result); + } + + return searchResults; + } +} diff --git a/Jellyfin.Plugin.Vgmdb/VgmdbApi.cs b/Jellyfin.Plugin.Vgmdb/VgmdbApi.cs new file mode 100644 index 0000000..4876e7f --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/VgmdbApi.cs @@ -0,0 +1,41 @@ +using System.Net; +using System.Net.Http; +using System.Net.Http.Json; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Plugin.Vgmdb.Models; +using MediaBrowser.Common.Net; + +namespace Jellyfin.Plugin.Vgmdb; + +public class VgmdbApi +{ + private const string RootUrl = @"https://vgmdb.info/"; + private readonly IHttpClientFactory _httpClientFactory; + + public VgmdbApi(IHttpClientFactory httpClientFactory) + { + _httpClientFactory = httpClientFactory; + } + + public async Task GetArtistByIdAsync(int id, CancellationToken cancellationToken) + { + var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); + using var response = await httpClient.GetAsync(RootUrl + "/artist/" + id + "?format=json", cancellationToken).ConfigureAwait(false); + return await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + } + + public async Task GetAlbumById(int id, CancellationToken cancellationToken) + { + var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); + using var response = await httpClient.GetAsync(RootUrl + "/album/" + id + "?format=json", cancellationToken).ConfigureAwait(false); + return await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + } + + public async Task GetSearchResultsAsync(string name, CancellationToken cancellationToken) + { + var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); + using var response = await httpClient.GetAsync(RootUrl + "/search?format=json&q=" + WebUtility.UrlEncode(name), cancellationToken).ConfigureAwait(false); + return await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken).ConfigureAwait(false); + } +} diff --git a/Jellyfin.Plugin.Vgmdb/VgmdbPlugin.cs b/Jellyfin.Plugin.Vgmdb/VgmdbPlugin.cs new file mode 100644 index 0000000..85cb996 --- /dev/null +++ b/Jellyfin.Plugin.Vgmdb/VgmdbPlugin.cs @@ -0,0 +1,21 @@ +using System; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Plugins; +using MediaBrowser.Model.Serialization; + +namespace Jellyfin.Plugin.Vgmdb; + +/// +public class VgmdbPlugin : BasePlugin +{ + public VgmdbPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) + : base(applicationPaths, xmlSerializer) + { + } + + /// + public override string Name => "VGMdb"; + + /// + public override Guid Id => Guid.Parse("44616595-5798-47ad-8658-3c09f3030505"); +} diff --git a/jellyfin.ruleset b/jellyfin.ruleset new file mode 100644 index 0000000..8af791c --- /dev/null +++ b/jellyfin.ruleset @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ExternalIds/VgmdbAlbumExternalId.cs b/src/ExternalIds/VgmdbAlbumExternalId.cs deleted file mode 100644 index 7e6b103..0000000 --- a/src/ExternalIds/VgmdbAlbumExternalId.cs +++ /dev/null @@ -1,24 +0,0 @@ -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; - -namespace Jellyfin.Plugin.Vgmdb.ExternalIds -{ - /// - // ReSharper disable once ClassNeverInstantiated.Global - public class VgmdbAlbumExternalId : IExternalId - { - public const string ExternalId = "VGMdbAlbum"; - - public string ProviderName => "VGMdb Album"; - - public string Key => ExternalId; - - public ExternalIdMediaType? Type => ExternalIdMediaType.Album; - - public string UrlFormatString => "https://vgmdb.net/album/{0}"; - - public bool Supports(IHasProviderIds item) => item is MusicAlbum; - } -} \ No newline at end of file diff --git a/src/ExternalIds/VgmdbArtistExternalId.cs b/src/ExternalIds/VgmdbArtistExternalId.cs deleted file mode 100644 index cceec03..0000000 --- a/src/ExternalIds/VgmdbArtistExternalId.cs +++ /dev/null @@ -1,24 +0,0 @@ -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; - -namespace Jellyfin.Plugin.Vgmdb.ExternalIds -{ - /// - // ReSharper disable once ClassNeverInstantiated.Global - public class VgmdbArtistExternalId : IExternalId - { - public const string ExternalId = "VGMdbArtist"; - - public string ProviderName => "VGMdb Artist"; - - public string Key => ExternalId; - - public ExternalIdMediaType? Type => ExternalIdMediaType.Album; - - public string UrlFormatString => "https://vgmdb.net/artist/{0}"; - - public bool Supports(IHasProviderIds item) => item is MusicArtist; - } -} \ No newline at end of file diff --git a/src/Models/AlbumResponse.cs b/src/Models/AlbumResponse.cs deleted file mode 100644 index 99057de..0000000 --- a/src/Models/AlbumResponse.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; - -namespace Jellyfin.Plugin.Vgmdb.Models -{ - public class AlbumResponse - { - public LocalizedString names { get; set; } - public string picture_full { get; set; } - public string picture_small { get; set; } - public string picture_thumb { get; set; } - public string link { get; set; } - public string notes { get; set; } - - public string release_date { get; set; } - - public List categories { get; set; } - public List organizations { get; set; } - - public int Id => int.Parse(link.Replace("album/", "")); - } -} \ No newline at end of file diff --git a/src/Models/ArtistResponse.cs b/src/Models/ArtistResponse.cs deleted file mode 100644 index 3399141..0000000 --- a/src/Models/ArtistResponse.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Jellyfin.Plugin.Vgmdb.Models -{ - public class ArtistResponse - { - public string name { get; set; } - public string picture_full { get; set; } - public string picture_small { get; set; } - public string link { get; set; } - public string notes { get; set; } - - public int Id => int.Parse(link.Replace("artist/", "")); - } -} \ No newline at end of file diff --git a/src/Models/LocalizedString.cs b/src/Models/LocalizedString.cs deleted file mode 100644 index bb8d5ac..0000000 --- a/src/Models/LocalizedString.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Jellyfin.Plugin.Vgmdb.Models -{ - public class LocalizedString - { - public string en { get; set; } - public string ja { get; set; } - public string jaLatn { get; set; } - - public string GetPreferred() - { - return jaLatn ?? en ?? ja; - } - } -} \ No newline at end of file diff --git a/src/Models/Organisation.cs b/src/Models/Organisation.cs deleted file mode 100644 index 17f687f..0000000 --- a/src/Models/Organisation.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Jellyfin.Plugin.Vgmdb.Models -{ - public class Organisation - { - public string link { get; set; } - public LocalizedString names { get; set; } - public string role { get; set; } - - public int Id => int.Parse(link.Replace("org/", "")); - } -} \ No newline at end of file diff --git a/src/Models/SearchResponse.cs b/src/Models/SearchResponse.cs deleted file mode 100644 index 01b4ef9..0000000 --- a/src/Models/SearchResponse.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Jellyfin.Plugin.Vgmdb.Models -{ - public class SearchResponse - { - public SearchResponseResults results { get; set; } - } -} \ No newline at end of file diff --git a/src/Models/SearchResponseResults.cs b/src/Models/SearchResponseResults.cs deleted file mode 100644 index 1d4fd21..0000000 --- a/src/Models/SearchResponseResults.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace Jellyfin.Plugin.Vgmdb.Models -{ - public class SearchResponseResults - { - public List albums { get; set; } - public List artists { get; set; } - } -} \ No newline at end of file diff --git a/src/Models/SearchResponseResultsAlbum.cs b/src/Models/SearchResponseResultsAlbum.cs deleted file mode 100644 index 6ce02f9..0000000 --- a/src/Models/SearchResponseResultsAlbum.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Jellyfin.Plugin.Vgmdb.Models -{ - public class SearchResponseResultsAlbum - { - public string catalog { get; set; } - public string link { get; set; } - public string release_date { get; set; } - public LocalizedString titles { get; set; } - - public int Id => int.Parse(link.Replace("album/", "")); - } -} \ No newline at end of file diff --git a/src/Models/SearchResponseResultsArtist.cs b/src/Models/SearchResponseResultsArtist.cs deleted file mode 100644 index fed3ffd..0000000 --- a/src/Models/SearchResponseResultsArtist.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace Jellyfin.Plugin.Vgmdb.Models -{ - public class SearchResponseResultsArtist - { - public List aliases { get; set; } - public string link { get; set; } - public LocalizedString names { get; set; } - - public int Id => int.Parse(link.Replace("artist/", "")); - } -} \ No newline at end of file diff --git a/src/Plugin.cs b/src/Plugin.cs deleted file mode 100644 index 9307b5c..0000000 --- a/src/Plugin.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Plugins; -using MediaBrowser.Model.Serialization; - -namespace Jellyfin.Plugin.Vgmdb -{ - /// - // ReSharper disable once UnusedMember.Global - public class Plugin : BasePlugin - { - public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) : base(applicationPaths, xmlSerializer) - { - } - - public override string Name => "VGMdb"; - public override Guid Id => Guid.Parse("44616595-5798-47ad-8658-3c09f3030505"); - } -} \ No newline at end of file diff --git a/src/PluginConfiguration.cs b/src/PluginConfiguration.cs deleted file mode 100644 index f193951..0000000 --- a/src/PluginConfiguration.cs +++ /dev/null @@ -1,10 +0,0 @@ -using MediaBrowser.Model.Plugins; - -namespace Jellyfin.Plugin.Vgmdb -{ - /// - // ReSharper disable once ClassNeverInstantiated.Global - public class PluginConfiguration : BasePluginConfiguration - { - } -} \ No newline at end of file diff --git a/src/Providers/Images/VgmdbAlbumImageProvider.cs b/src/Providers/Images/VgmdbAlbumImageProvider.cs deleted file mode 100644 index 7bad4af..0000000 --- a/src/Providers/Images/VgmdbAlbumImageProvider.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections.Generic; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Plugin.Vgmdb.ExternalIds; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; - -namespace Jellyfin.Plugin.Vgmdb.Providers.Images -{ - public class VgmdbAlbumImageProvider : IRemoteImageProvider - { - private readonly IHttpClientFactory _httpClientFactory; - private readonly VgmdbApi _api; - - public VgmdbAlbumImageProvider(IHttpClientFactory httpClientFactory) - { - _httpClientFactory = httpClientFactory; - _api = new VgmdbApi(httpClientFactory); - } - - public string Name => "VGMdb"; - - public Task GetImageResponse(string url, CancellationToken cancellationToken) - { - return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken); - } - - public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) - { - var images = new List(); - - var id = item.GetProviderId(VgmdbAlbumExternalId.ExternalId); - - //todo use a search to find id - if (id == null) return images; - var album = await _api.GetAlbumById(int.Parse(id), cancellationToken); - - images.Add(new RemoteImageInfo - { - Url = album.picture_full, - ThumbnailUrl = album.picture_small - }); - - return images; - } - - public IEnumerable GetSupportedImages(BaseItem item) - { - return new List - { - ImageType.Primary - }; - } - - public bool Supports(BaseItem item) => item is MusicAlbum; - } -} diff --git a/src/Providers/Images/VgmdbArtistImageProvider.cs b/src/Providers/Images/VgmdbArtistImageProvider.cs deleted file mode 100644 index de84cc7..0000000 --- a/src/Providers/Images/VgmdbArtistImageProvider.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Collections.Generic; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Plugin.Vgmdb.ExternalIds; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; - -namespace Jellyfin.Plugin.Vgmdb.Providers.Images -{ - public class VgmdbArtistImageProvider : IRemoteImageProvider - { - private readonly IHttpClientFactory _httpClientFactory; - private readonly VgmdbApi _api; - - public VgmdbArtistImageProvider(IHttpClientFactory httpClientFactory) - { - _httpClientFactory = httpClientFactory; - _api = new VgmdbApi(httpClientFactory); - } - - public string Name => "VGMdb"; - - public Task GetImageResponse(string url, CancellationToken cancellationToken) - { - return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url); - } - - public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) - { - var images = new List(); - - var id = item.GetProviderId(VgmdbArtistExternalId.ExternalId); - - //todo use a search to find id - if (id == null) return images; - - var artist = await _api.GetArtistById(int.Parse(id), cancellationToken); - - images.Add(new RemoteImageInfo - { - Url = artist.picture_full, - ThumbnailUrl = artist.picture_small - }); - - return images; - } - - public IEnumerable GetSupportedImages(BaseItem item) - { - return new List - { - ImageType.Primary - }; - } - - public bool Supports(BaseItem item) => item is MusicArtist; - } -} diff --git a/src/Providers/Info/VgmdbAlbumProvider.cs b/src/Providers/Info/VgmdbAlbumProvider.cs deleted file mode 100644 index de7a4ea..0000000 --- a/src/Providers/Info/VgmdbAlbumProvider.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Collections.Generic; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Plugin.Vgmdb.ExternalIds; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; - -namespace Jellyfin.Plugin.Vgmdb.Providers.Info -{ - // todo: implement IHasOrder, but find out what it does first - public class VgmdbAlbumProvider : IRemoteMetadataProvider - { - private readonly IHttpClientFactory _httpClientFactory; - private readonly VgmdbApi _api; - - public VgmdbAlbumProvider(IHttpClientFactory httpClientFactory) - { - _httpClientFactory = httpClientFactory; - _api = new VgmdbApi(httpClientFactory); - } - - public string Name => "VGMdb"; - - public Task GetImageResponse(string url, CancellationToken cancellationToken) - { - return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url); - } - - public async Task GetAlbumById(int id, CancellationToken cancellationToken) - { - var response = await _api.GetAlbumById(id, cancellationToken); - - if (response == null) return null; - - var album = new MusicAlbum - { - ProviderIds = - { - [VgmdbAlbumExternalId.ExternalId] = response.Id.ToString() - }, - Name = response.names.GetPreferred() - }; - - //todo better date parsing - int.TryParse(response.release_date.Split('-')[0], out var productionYear); - if (productionYear > 0) album.ProductionYear = productionYear; - - var image = new ItemImageInfo - { - Path = response.picture_full, - Type = ImageType.Primary - }; - album.SetImage(image, 0); - - album.Overview = response.notes; - - if (response.categories != null) - { - foreach (var category in response.categories) - { - album.AddGenre(category); - } - } - - if (response.organizations != null) - { - foreach (var organisation in response.organizations) - { - album.AddStudio(organisation.names.GetPreferred()); - } - } - - return album; - } - - public async Task GetId(AlbumInfo info, CancellationToken cancellationToken) - { - var providedId = info.GetProviderId(VgmdbAlbumExternalId.ExternalId); - if (providedId != null) return int.Parse(providedId); - - var searchResults = await GetSearchResults(info, cancellationToken); - - foreach (var result in searchResults) - { - var id = result.GetProviderId(VgmdbAlbumExternalId.ExternalId); - - if (id != null) return int.Parse(id); - } - - return null; - } - - public async Task> GetMetadata(AlbumInfo info, CancellationToken cancellationToken) - { - var id = await GetId(info, cancellationToken); - - if (id != null) - { - return new MetadataResult - { - Item = await GetAlbumById((int) id, cancellationToken) - }; - } - - return new MetadataResult(); - } - - public async Task> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken) - { - var response = await _api.GetSearchResults(searchInfo.Name, cancellationToken); - - var searchResults = new List(); - if (response == null) return null; - - foreach (var albumEntry in response.results.albums) - { - var album = await GetAlbumById(albumEntry.Id, cancellationToken); - var result = new RemoteSearchResult - { - ProviderIds = album.ProviderIds, - Name = album.Name, - ProductionYear = album.ProductionYear, - ImageUrl = album.PrimaryImagePath - }; - - searchResults.Add(result); - } - - return searchResults; - } - } -} diff --git a/src/Providers/Info/VgmdbArtistProvider.cs b/src/Providers/Info/VgmdbArtistProvider.cs deleted file mode 100644 index 746bc73..0000000 --- a/src/Providers/Info/VgmdbArtistProvider.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System.Collections.Generic; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Plugin.Vgmdb.ExternalIds; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; - -namespace Jellyfin.Plugin.Vgmdb.Providers.Info -{ - // todo: implement IHasOrder, but find out what it does first - public class VgmdbArtistProvider : IRemoteMetadataProvider - { - private readonly IHttpClientFactory _httpClientFactory; - private readonly VgmdbApi _api; - - public VgmdbArtistProvider(IHttpClientFactory httpClientFactory) - { - _httpClientFactory = httpClientFactory; - _api = new VgmdbApi(httpClientFactory); - } - - public string Name => "VGMdb"; - - public Task GetImageResponse(string url, CancellationToken cancellationToken) - { - return _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url); - } - - public async Task GetArtistById(int id, CancellationToken cancellationToken) - { - var response = await _api.GetArtistById(id, cancellationToken); - - if (response == null) return null; - - var artist = new MusicArtist - { - ProviderIds = - { - [VgmdbArtistExternalId.ExternalId] = response.Id.ToString() - }, - Name = response.name - }; - - var image = new ItemImageInfo - { - Path = response.picture_full, - Type = ImageType.Primary - }; - artist.SetImage(image, 0); - - artist.Overview = response.notes; - - return artist; - } - - public async Task GetId(ArtistInfo info, CancellationToken cancellationToken) - { - var providedId = info.GetProviderId(VgmdbArtistExternalId.ExternalId); - if (providedId != null) return int.Parse(providedId); - - var searchResults = await GetSearchResults(info, cancellationToken); - - foreach (var result in searchResults) - { - var id = result.GetProviderId(VgmdbArtistExternalId.ExternalId); - - if (id != null) return int.Parse(id); - } - - return null; - } - - public async Task> GetMetadata(ArtistInfo info, CancellationToken cancellationToken) - { - var id = await GetId(info, cancellationToken); - - if (id != null) - { - return new MetadataResult - { - Item = await GetArtistById((int) id, cancellationToken) - }; - } - - return new MetadataResult(); - } - - public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) - { - var response = await _api.GetSearchResults(searchInfo.Name, cancellationToken); - - var searchResults = new List(); - if (response == null) return null; - - foreach (var artistEntry in response.results.artists) - { - var artist = await GetArtistById(artistEntry.Id, cancellationToken); - var result = new RemoteSearchResult - { - ProviderIds = artist.ProviderIds, - Name = artist.Name, - ImageUrl = artist.PrimaryImagePath - }; - - searchResults.Add(result); - } - - return searchResults; - } - } -} diff --git a/src/VgmdbApi.cs b/src/VgmdbApi.cs deleted file mode 100644 index abd093c..0000000 --- a/src/VgmdbApi.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Net; -using System.Net.Http; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Plugin.Vgmdb.Models; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Serialization; - -namespace Jellyfin.Plugin.Vgmdb -{ - public class VgmdbApi - { - private readonly IHttpClientFactory _httpClientFactory; - private const string RootUrl = @"https://vgmdb.info/"; - - public VgmdbApi(IHttpClientFactory httpClientFactory) - { - _httpClientFactory = httpClientFactory; - } - - public async Task GetArtistById(int id, CancellationToken cancellationToken) - { - var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); - using (var response = await httpClient.GetAsync(RootUrl + "/artist/" + id + "?format=json", cancellationToken).ConfigureAwait(false)) - { - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - return await JsonSerializer.DeserializeAsync(stream).ConfigureAwait(false); - } - } - - public async Task GetAlbumById(int id, CancellationToken cancellationToken) - { - var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); - using (var response = await httpClient.GetAsync(RootUrl + "/album/" + id + "?format=json", cancellationToken).ConfigureAwait(false)) - { - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - return await JsonSerializer.DeserializeAsync(stream).ConfigureAwait(false); - } - } - - public async Task GetSearchResults(string name, CancellationToken cancellationToken) - { - var httpClient = _httpClientFactory.CreateClient(NamedClient.Default); - using (var response = await httpClient.GetAsync(RootUrl + "/search?format=json&q=" + WebUtility.UrlEncode(name), cancellationToken).ConfigureAwait(false)) - { - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - return await JsonSerializer.DeserializeAsync(stream).ConfigureAwait(false); - } - } - } -}