using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MetaBrainz.Common;
using MetaBrainz.MusicBrainz;
using MetaBrainz.MusicBrainz.Interfaces.Entities;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.Plugins.MusicBrainz;
///
/// Helpers for talking to MusicBrainz with identifiers that are not guaranteed to be valid.
///
internal static class MusicBrainzQueryExtensions
{
///
/// Parses a MusicBrainz identifier, which may come from user-supplied tags or NFO files and is therefore not
/// guaranteed to be a valid GUID.
///
/// The identifier to parse.
/// The type of entity the identifier refers to, used for logging.
/// The logger.
/// The parsed identifier, or if it is missing or malformed.
public static Guid? ParseMusicBrainzId(string? id, string entityType, ILogger logger)
{
if (string.IsNullOrWhiteSpace(id))
{
return null;
}
if (!Guid.TryParse(id, out var parsedId))
{
logger.LogDebug("Ignoring malformed MusicBrainz {EntityType} id {Id}", entityType, id);
return null;
}
return parsedId;
}
///
/// Looks up a release, treating an unknown identifier as missing data rather than an error.
///
/// The MusicBrainz query client.
/// The release identifier.
/// The additional data to include in the lookup.
/// The logger.
/// The cancellation token.
/// The release, or if MusicBrainz does not have it.
public static Task LookupReleaseOrNullAsync(this Query query, Guid releaseId, Include include, ILogger logger, CancellationToken cancellationToken)
=> NotFoundAsNullAsync(
() => query.LookupReleaseAsync(releaseId, include, cancellationToken),
"release",
releaseId,
logger);
///
/// Looks up a release group, treating an unknown identifier as missing data rather than an error.
///
/// The MusicBrainz query client.
/// The release group identifier.
/// The additional data to include in the lookup.
/// The logger.
/// The cancellation token.
/// The release group, or if MusicBrainz does not have it.
public static Task LookupReleaseGroupOrNullAsync(this Query query, Guid releaseGroupId, Include include, ILogger logger, CancellationToken cancellationToken)
=> NotFoundAsNullAsync(
() => query.LookupReleaseGroupAsync(releaseGroupId, include, null, cancellationToken),
"release group",
releaseGroupId,
logger);
///
/// Looks up an artist, treating an unknown identifier as missing data rather than an error.
///
/// The MusicBrainz query client.
/// The artist identifier.
/// The additional data to include in the lookup.
/// The logger.
/// The cancellation token.
/// The artist, or if MusicBrainz does not have it.
public static Task LookupArtistOrNullAsync(this Query query, Guid artistId, Include include, ILogger logger, CancellationToken cancellationToken)
=> NotFoundAsNullAsync(
() => query.LookupArtistAsync(artistId, include, null, null, cancellationToken),
"artist",
artistId,
logger);
///
/// Runs a lookup, mapping a "not found" response to . Identifiers stored on a library item
/// can refer to entities that no longer exist in MusicBrainz, which is not an error worth failing a refresh over.
///
/// The type of entity being looked up.
/// The lookup to run.
/// The type of entity being looked up, used for logging.
/// The identifier being looked up, used for logging.
/// The logger.
/// The entity, or if MusicBrainz does not have it.
private static async Task NotFoundAsNullAsync(Func> lookup, string entityType, Guid id, ILogger logger)
where T : class
{
try
{
return await lookup().ConfigureAwait(false);
}
catch (HttpError ex) when (ex.Status == HttpStatusCode.NotFound)
{
logger.LogDebug("MusicBrainz has no {EntityType} with id {Id}", entityType, id);
return null;
}
}
}