Support artist type from discogs api

This commit is contained in:
aglowinthefield 2025-12-10 17:28:06 -05:00
parent 5122e8e2f3
commit d900890e6b
No known key found for this signature in database
4 changed files with 177 additions and 18 deletions

View file

@ -55,7 +55,65 @@ public void should_parse_release_items()
}
[Test]
public void should_ignore_non_release_items()
public void should_parse_artist_items()
{
const string resourceUrl = "https://api.discogs.com/artists/3227";
GivenArtistDetails(resourceUrl, BuildArtistResponse("Silent Phase"));
var response = BuildListResponse(@"{
""items"": [
{
""type"": ""artist"",
""id"": 3227,
""display_title"": ""Silent Phase"",
""resource_url"": ""https://api.discogs.com/artists/3227""
}
]
}");
var items = _parser.ParseResponse(response);
items.Should().HaveCount(1);
items.First().Artist.Should().Be("Silent Phase");
items.First().Album.Should().BeNull();
}
[Test]
public void should_parse_mixed_release_and_artist_items()
{
const string releaseUrl = "https://api.discogs.com/releases/4674";
const string artistUrl = "https://api.discogs.com/artists/3227";
GivenReleaseDetails(releaseUrl, BuildReleaseResponse("Silent Phase", "The Rewired Mixes"));
GivenArtistDetails(artistUrl, BuildArtistResponse("Silent Phase"));
var response = BuildListResponse(@"{
""items"": [
{
""type"": ""release"",
""id"": 4674,
""display_title"": ""Silent Phase - The Rewired Mixes"",
""resource_url"": ""https://api.discogs.com/releases/4674""
},
{
""type"": ""artist"",
""id"": 3227,
""display_title"": ""Silent Phase"",
""resource_url"": ""https://api.discogs.com/artists/3227""
}
]
}");
var items = _parser.ParseResponse(response);
items.Should().HaveCount(2);
items.First().Artist.Should().Be("Silent Phase");
items.First().Album.Should().Be("The Rewired Mixes");
items.Last().Artist.Should().Be("Silent Phase");
items.Last().Album.Should().BeNull();
}
[Test]
public void should_ignore_non_release_and_non_artist_items()
{
var response = BuildListResponse(@"{
""items"": [
@ -96,6 +154,50 @@ public void should_skip_release_when_details_fail()
items.Should().BeEmpty();
}
[Test]
public void should_skip_artist_when_details_fail()
{
var response = BuildListResponse(@"{
""items"": [
{
""type"": ""artist"",
""id"": 3227,
""display_title"": ""Silent Phase"",
""resource_url"": ""https://api.discogs.com/artists/3227""
}
]
}");
_httpClient.Setup(c => c.Execute(It.IsAny<HttpRequest>()))
.Returns(new HttpResponse(new HttpRequest("https://api.discogs.com/artists/3227"), _defaultHeaders, string.Empty, HttpStatusCode.NotFound));
var items = _parser.ParseResponse(response);
items.Should().BeEmpty();
}
[Test]
public void should_skip_artist_when_name_is_missing()
{
const string resourceUrl = "https://api.discogs.com/artists/3227";
GivenArtistDetails(resourceUrl, @"{ ""id"": 3227 }");
var response = BuildListResponse(@"{
""items"": [
{
""type"": ""artist"",
""id"": 3227,
""display_title"": ""Silent Phase"",
""resource_url"": ""https://api.discogs.com/artists/3227""
}
]
}");
var items = _parser.ParseResponse(response);
items.Should().BeEmpty();
}
[Test]
public void should_throw_when_discogs_returns_html()
{
@ -122,6 +224,12 @@ private void GivenReleaseDetails(string resourceUrl, string payload, HttpStatusC
.Returns(new HttpResponse(new HttpRequest(resourceUrl), _defaultHeaders, payload, statusCode));
}
private void GivenArtistDetails(string resourceUrl, string payload, HttpStatusCode statusCode = HttpStatusCode.OK)
{
_httpClient.Setup(c => c.Execute(It.Is<HttpRequest>(r => r.Url.FullUri == resourceUrl)))
.Returns(new HttpResponse(new HttpRequest(resourceUrl), _defaultHeaders, payload, statusCode));
}
private static string BuildReleaseResponse(string artist, string title)
{
return $@"{{
@ -131,4 +239,12 @@ private static string BuildReleaseResponse(string artist, string title)
]
}}";
}
private static string BuildArtistResponse(string name)
{
return $@"{{
""name"": ""{name}"",
""id"": 3227
}}";
}
}

View file

@ -31,6 +31,12 @@ public class DiscogsReleaseArtist
public int Id { get; set; }
}
public class DiscogsArtistResponse
{
public string Name { get; set; }
public int Id { get; set; }
}
public class DiscogsWantlistResponse
{
public List<DiscogsWantlistItem> Wants { get; set; }

View file

@ -8,18 +8,11 @@
namespace NzbDrone.Core.ImportLists.Discogs;
public class DiscogsListsParser : IParseImportListResponse
public class DiscogsListsParser(DiscogsListsSettings settings, IHttpClient httpClient, Logger logger) : IParseImportListResponse
{
private readonly DiscogsListsSettings _settings;
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
public DiscogsListsParser(DiscogsListsSettings settings, IHttpClient httpClient, Logger logger)
{
_settings = settings;
_httpClient = httpClient;
_logger = logger;
}
private readonly DiscogsListsSettings _settings = settings;
private readonly IHttpClient _httpClient = httpClient;
private readonly Logger _logger = logger;
public IList<ImportListItemInfo> ParseResponse(ImportListResponse importListResponse)
{
@ -39,17 +32,29 @@ public IList<ImportListItemInfo> ParseResponse(ImportListResponse importListResp
foreach (var item in jsonResponse.Items)
{
if (item.Type == "release" && item.ResourceUrl.IsNotNullOrWhiteSpace())
if (item.ResourceUrl.IsNullOrWhiteSpace())
{
try
continue;
}
try
{
ImportListItemInfo itemInfo = null;
if (item.Type == "release")
{
var releaseInfo = FetchReleaseDetails(item.ResourceUrl);
items.AddIfNotNull(releaseInfo);
itemInfo = FetchReleaseDetails(item.ResourceUrl);
}
catch (Exception ex)
else if (item.Type == "artist")
{
_logger.Error(ex, "Discogs release details API call resulted in an unexpected exception");
itemInfo = FetchArtistDetails(item.ResourceUrl);
}
items.AddIfNotNull(itemInfo);
}
catch (Exception ex)
{
_logger.Error(ex, "Discogs API call resulted in an unexpected exception for {0} type item", item.Type ?? "unknown");
}
}
@ -67,4 +72,9 @@ private ImportListItemInfo FetchReleaseDetails(string resourceUrl)
{
return DiscogsParserHelper.FetchReleaseDetails(_httpClient, _settings.Token, resourceUrl);
}
private ImportListItemInfo FetchArtistDetails(string resourceUrl)
{
return DiscogsParserHelper.FetchArtistDetails(_httpClient, _settings.Token, resourceUrl);
}
}

View file

@ -37,6 +37,33 @@ public static ImportListItemInfo FetchReleaseDetails(IHttpClient httpClient, str
};
}
public static ImportListItemInfo FetchArtistDetails(IHttpClient httpClient, string token, string resourceUrl)
{
var request = new HttpRequestBuilder(resourceUrl)
.SetHeader("Authorization", $"Discogs token={token}")
.Build();
var response = httpClient.Execute(request);
if (response.StatusCode != HttpStatusCode.OK)
{
return null;
}
var artistResponse = Json.Deserialize<DiscogsArtistResponse>(response.Content);
if (artistResponse?.Name.IsNullOrWhiteSpace() == true)
{
return null;
}
return new ImportListItemInfo
{
Artist = artistResponse.Name,
Album = null // Artists don't have a specific album, just the artist name
};
}
public static void EnsureValidResponse(ImportListResponse importListResponse, string htmlContentMessage)
{
if (importListResponse.HttpResponse.StatusCode != HttpStatusCode.OK)