Skip to content

Commit

Permalink
Merge pull request #50 from Zastai/update-mappings
Browse files Browse the repository at this point in the history
Update the mappings to match current API results
  • Loading branch information
Zastai authored Dec 24, 2023
2 parents 4fd5515 + 6a7e7f3 commit 78f7ef1
Show file tree
Hide file tree
Showing 26 changed files with 426 additions and 56 deletions.
7 changes: 6 additions & 1 deletion MetaBrainz.ListenBrainz/Interfaces/IArtistCountryInfo.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
using System.Collections.Generic;

using JetBrains.Annotations;

namespace MetaBrainz.ListenBrainz.Interfaces;

/// <summary>Information about listens for artists of a particular country.</summary>
/// <summary>Information about listens for artists from a particular country.</summary>
[PublicAPI]
public interface IArtistCountryInfo {

/// <summary>The number of (distinct) artists from this country that were listened to.</summary>
int ArtistCount { get; }

/// <summary>Information about the artists from this country that were listened to.</summary>
IReadOnlyList<IArtistInfo>? Artists { get; }

/// <summary>The 3-letter country code (ISO 3166-1 alpha-3).</summary>
string Country { get; }

Expand Down
22 changes: 22 additions & 0 deletions MetaBrainz.ListenBrainz/Interfaces/IArtistCredit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;

using JetBrains.Annotations;

namespace MetaBrainz.ListenBrainz.Interfaces;

/// <summary>An entry in an artist credit taken from the MusicBrainz database.</summary>
[PublicAPI]
public interface IArtistCredit {

/// <summary>The name specified for the artist in the credit.</summary>
string CreditedName { get; }

/// <summary>The MusicBrainz IDs for the artist.</summary>
Guid Id { get; }

/// <summary>
/// The phrase used to connect this entry to the next one in the credit, or to end the credit if this is the last entry.
/// </summary>
string? JoinPhrase { get; }

}
6 changes: 6 additions & 0 deletions MetaBrainz.ListenBrainz/Interfaces/IArtistInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ namespace MetaBrainz.ListenBrainz.Interfaces;
[PublicAPI]
public interface IArtistInfo : IJsonBasedObject {

/// <summary>The MusicBrainz ID for the artist, if available.</summary>
Guid? Id { get; }

/// <summary>The MusicBrainz IDs for the artist, if available.</summary>
/// <remarks>
/// This may be obsolete; the current API only ever seems to return a single ID, which will be available in <see cref="Id"/>.
/// </remarks>
IReadOnlyList<Guid>? Ids { get; }

/// <summary>The number of times the artist's tracks were listened to.</summary>
Expand Down
21 changes: 13 additions & 8 deletions MetaBrainz.ListenBrainz/Interfaces/IFetchedListens.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@ public interface IFetchedListens : IJsonBasedObject {
/// <summary>The listens that were fetched.</summary>
IReadOnlyList<IListen> Listens { get; }

/// <summary>The timestamp of the newest listen included in <see cref="Listens"/>.</summary>
DateTimeOffset Timestamp { get; }

/// <summary>
/// The timestamp of the newest listen included in <see cref="Listens"/>, expressed as the number of seconds since
/// <see cref="UnixTime.Epoch">the Unix time epoch</see>.
/// </summary>
long UnixTimestamp { get; }
/// <summary>The timestamp of the newest listen recorded for the user.</summary>
/// <remarks>
/// This looks at the entire dataset, not just the date range that may have been specified in the request. The listen(s) with this
/// timestamp will not necessarily be included in <see cref="Listens"/>.
/// </remarks>
DateTimeOffset Newest { get; }

/// <summary>The timestamp of the oldest listen recorded for the user.</summary>
/// <remarks>
/// This looks at the entire dataset, not just the date range that may have been specified in the request. The listen(s) with this
/// timestamp will not necessarily be included in <see cref="Listens"/>.
/// </remarks>
DateTimeOffset Oldest { get; }

/// <summary>The MusicBrainz ID of the user for which the listens were fetched.</summary>
string User { get; }
Expand Down
11 changes: 3 additions & 8 deletions MetaBrainz.ListenBrainz/Interfaces/IListen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,15 @@ public interface IListen : IJsonBasedObject {
/// <summary>The timestamp at which the listen information was inserted in the database.</summary>
DateTimeOffset InsertedAt { get; }

/// <summary>The timestamp at which the listen occurred.</summary>
DateTimeOffset ListenedAt { get; }

/// <summary>The MessyBrainz ID for the recording that was listened to.</summary>
Guid MessyRecordingId { get; }

/// <summary>The timestamp at which the listen occurred.</summary>
DateTimeOffset Timestamp { get; }

/// <summary>Information about the track that was listened to.</summary>
ITrackInfo Track { get; }

/// <summary>
/// The timestamp for the listen, expressed as the number of seconds since <see cref="UnixTime.Epoch">the Unix time epoch</see>.
/// </summary>
long UnixTimestamp { get; }

/// <summary>The MusicBrainz ID of the user who submitted the listen.</summary>
string User { get; }

Expand Down
15 changes: 15 additions & 0 deletions MetaBrainz.ListenBrainz/Interfaces/IMusicBrainzIdMappings.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
using System;
using System.Collections.Generic;

using JetBrains.Annotations;

namespace MetaBrainz.ListenBrainz.Interfaces;

/// <summary>
/// Mappings to MusicBrainz IDs as determined by ListenBrainz.<br/>
/// There are similar fields in <see cref="IAdditionalInfo"/>, but those are values supplied at submission time by the client.
/// </summary>
[PublicAPI]
public interface IMusicBrainzIdMappings {

/// <summary>The MusicBrainz IDs for the track's artists.</summary>
IReadOnlyList<Guid>? ArtistIds { get; }

/// <summary>The internal ID for the track's release in the CoverArt Archive.</summary>
long? CoverArtId { get; }

/// <summary>The MusicBrainz ID for the track's release in the CoverArt Archive.</summary>
Guid? CoverArtReleaseId { get; }

/// <summary>The MusicBrainz credits for the track's artists.</summary>
IReadOnlyList<IArtistCredit>? Credits { get; }

/// <summary>The MusicBrainz ID for the track's recording.</summary>
Guid? RecordingId { get; }

/// <summary>The name for the track's recording in the MusicBrainz database.</summary>
string? RecordingName { get; }

/// <summary>The MusicBrainz ID for the track's release.</summary>
Guid? ReleaseId { get; }

Expand Down
9 changes: 9 additions & 0 deletions MetaBrainz.ListenBrainz/Interfaces/IRecordingInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ public interface IRecordingInfo {
/// <summary>The recording's artist's name, if available.</summary>
string? ArtistName { get; }

/// <summary>The internal ID for the recording's release in the CoverArt Archive.</summary>
long? CoverArtId { get; }

/// <summary>The MusicBrainz ID for the recording's release in the CoverArt Archive.</summary>
Guid? CoverArtReleaseId { get; }

/// <summary>The MusicBrainz credits for the recording's artists.</summary>
IReadOnlyList<IArtistCredit>? Credits { get; }

/// <summary>The number of times the recording was listened to.</summary>
int ListenCount { get; }

Expand Down
9 changes: 9 additions & 0 deletions MetaBrainz.ListenBrainz/Interfaces/IReleaseInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ public interface IReleaseInfo {
/// <summary>The release's artist's name, if available.</summary>
string? ArtistName { get; }

/// <summary>The internal ID for the track's release in the CoverArt Archive.</summary>
long? CoverArtId { get; }

/// <summary>The MusicBrainz ID for the track's release in the CoverArt Archive.</summary>
Guid? CoverArtReleaseId { get; }

/// <summary>The MusicBrainz credits for the track's artists.</summary>
IReadOnlyList<IArtistCredit>? Credits { get; }

/// <summary>The MusicBrainz ID for the release, if available.</summary>
Guid? Id { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using MetaBrainz.Common.Json;
using MetaBrainz.Common.Json.Converters;
using MetaBrainz.ListenBrainz.Interfaces;
using MetaBrainz.ListenBrainz.Objects;

namespace MetaBrainz.ListenBrainz.Json.Readers;
Expand All @@ -14,6 +15,7 @@ internal class ArtistCountryInfoReader : ObjectReader<ArtistCountryInfo> {

protected override ArtistCountryInfo ReadObjectContents(ref Utf8JsonReader reader, JsonSerializerOptions options) {
int? artistCount = null;
IReadOnlyList<IArtistInfo>? artists = null;
int? listenCount = null;
string? country = null;
Dictionary<string, object?>? rest = null;
Expand All @@ -22,6 +24,9 @@ protected override ArtistCountryInfo ReadObjectContents(ref Utf8JsonReader reade
try {
reader.Read();
switch (prop) {
case "artists":
artists = reader.ReadList(ArtistInfoReader.Instance, options);
break;
case "artist_count":
artistCount = reader.GetInt32();
break;
Expand Down Expand Up @@ -52,6 +57,7 @@ protected override ArtistCountryInfo ReadObjectContents(ref Utf8JsonReader reade
throw new JsonException("Expected listen count not found or null.");
}
return new ArtistCountryInfo(artistCount.Value, country, listenCount.Value) {
Artists = artists,
UnhandledProperties = rest,
};
}
Expand Down
59 changes: 59 additions & 0 deletions MetaBrainz.ListenBrainz/Json/Readers/ArtistCreditReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Text.Json;

using MetaBrainz.Common.Json;
using MetaBrainz.Common.Json.Converters;
using MetaBrainz.ListenBrainz.Objects;

namespace MetaBrainz.ListenBrainz.Json.Readers;

internal class ArtistCreditReader : ObjectReader<ArtistCredit> {

public static readonly ArtistCreditReader Instance = new();

protected override ArtistCredit ReadObjectContents(ref Utf8JsonReader reader, JsonSerializerOptions options) {
string? creditedName = null;
string? joinPhrase = null;
Guid? id = null;
Dictionary<string, object?>? rest = null;
while (reader.TokenType == JsonTokenType.PropertyName) {
var prop = reader.GetPropertyName();
try {
reader.Read();
switch (prop) {
case "artist_credit_name":
creditedName = reader.GetString();
break;
case "artist_mbid":
id = reader.GetOptionalGuid();
break;
case "join_phrase":
joinPhrase = reader.GetString();
break;
default:
rest ??= new Dictionary<string, object?>();
rest[prop] = reader.GetOptionalObject(options);
break;
}
}
catch (Exception e) {
throw new JsonException($"Failed to deserialize the '{prop}' property.", e);
}
reader.Read();
}
if (creditedName is null) {
throw new JsonException("Expected artist credit name not found or null.");
}
if (id is null) {
throw new JsonException("Expected artist ID not found or null.");
}
if (joinPhrase is null) {
throw new JsonException("Expected join phrase not found or null.");
}
return new ArtistCredit(creditedName, id.Value, joinPhrase) {
UnhandledProperties = rest,
};
}

}
5 changes: 5 additions & 0 deletions MetaBrainz.ListenBrainz/Json/Readers/ArtistInfoReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal class ArtistInfoReader : ObjectReader<ArtistInfo> {

protected override ArtistInfo ReadObjectContents(ref Utf8JsonReader reader, JsonSerializerOptions options) {
int? listenCount = null;
Guid? mbid = null;
IReadOnlyList<Guid>? mbids = null;
Guid? msid = null;
string? name = null;
Expand All @@ -23,6 +24,9 @@ protected override ArtistInfo ReadObjectContents(ref Utf8JsonReader reader, Json
try {
reader.Read();
switch (prop) {
case "artist_mbid":
mbid = reader.GetOptionalGuid();
break;
case "artist_mbids":
mbids = reader.ReadList<Guid>(options);
break;
Expand Down Expand Up @@ -53,6 +57,7 @@ protected override ArtistInfo ReadObjectContents(ref Utf8JsonReader reader, Json
throw new JsonException("Expected artist name not found or null.");
}
return new ArtistInfo(name, listenCount.Value) {
Id = mbid,
Ids = mbids,
MessyId = msid,
UnhandledProperties = rest,
Expand Down
15 changes: 11 additions & 4 deletions MetaBrainz.ListenBrainz/Json/Readers/FetchedListensReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ internal sealed class FetchedListensReader : PayloadReader<FetchedListens> {
protected override FetchedListens ReadPayload(ref Utf8JsonReader reader, JsonSerializerOptions options) {
ushort? count = null;
IReadOnlyList<IListen>? listens = null;
long? newest = null;
long? oldest = null;
string? user = null;
long? ts = null;
Dictionary<string, object?>? rest = null;
while (reader.TokenType == JsonTokenType.PropertyName) {
var prop = reader.GetPropertyName();
Expand All @@ -30,7 +31,10 @@ protected override FetchedListens ReadPayload(ref Utf8JsonReader reader, JsonSer
listens = reader.ReadList(ListenReader.Instance, options);
break;
case "latest_listen_ts":
ts = reader.GetInt64();
newest = reader.GetOptionalInt64();
break;
case "oldest_listen_ts":
oldest = reader.GetOptionalInt64();
break;
case "user_id":
user = reader.GetString();
Expand All @@ -50,10 +54,13 @@ protected override FetchedListens ReadPayload(ref Utf8JsonReader reader, JsonSer
if (user is null) {
throw new JsonException("Expected user id not found or null.");
}
if (ts is null) {
if (newest is null) {
throw new JsonException("Expected latest-listen timestamp not found or null.");
}
return new FetchedListens(listens, ts.Value, user) {
if (oldest is null) {
throw new JsonException("Expected oldest-listen timestamp not found or null.");
}
return new FetchedListens(listens, newest.Value, oldest.Value, user) {
UnhandledProperties = rest
};
}
Expand Down
14 changes: 7 additions & 7 deletions MetaBrainz.ListenBrainz/Json/Readers/ListenReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ protected override Listen ReadObjectContents(ref Utf8JsonReader reader, JsonSeri
Guid? msid = null;
ITrackInfo? track = null;
string? user = null;
long? ts = null;
long? listened = null;
Dictionary<string, object?>? rest = null;
while (reader.TokenType == JsonTokenType.PropertyName) {
var prop = reader.GetPropertyName();
try {
reader.Read();
switch (prop) {
case "inserted_at":
inserted = reader.GetInt64();
inserted = reader.GetOptionalInt64();
break;
case "listened_at":
ts = reader.GetInt64();
listened = reader.GetOptionalInt64();
break;
case "recording_msid":
msid = reader.GetGuid();
Expand All @@ -54,6 +54,9 @@ protected override Listen ReadObjectContents(ref Utf8JsonReader reader, JsonSeri
if (inserted is null) {
throw new JsonException("Expected inserted-at timestamp not found or null.");
}
if (listened is null) {
throw new JsonException("Expected listened-at timestamp not found or null.");
}
if (msid is null) {
throw new JsonException("Expected MessyBrainz recording id not found or null.");
}
Expand All @@ -63,10 +66,7 @@ protected override Listen ReadObjectContents(ref Utf8JsonReader reader, JsonSeri
if (user is null) {
throw new JsonException("Expected user name not found or null.");
}
if (ts is null) {
throw new JsonException("Expected listened-at timestamp not found or null.");
}
return new Listen(inserted.Value, msid.Value, ts.Value, track, user) {
return new Listen(inserted.Value, listened.Value, msid.Value, track, user) {
UnhandledProperties = rest
};
}
Expand Down
Loading

0 comments on commit 78f7ef1

Please sign in to comment.