162 lines
7.0 KiB
C#
162 lines
7.0 KiB
C#
namespace Webzine.Business.Seeders;
|
|
|
|
using System.Net.Http.Headers;
|
|
using System.Net.Http.Json;
|
|
using System.Text;
|
|
|
|
using Microsoft.Extensions.Options;
|
|
|
|
using Webzine.Business.DTOs.Spotify;
|
|
using Webzine.Business.Mappers.Spotify;
|
|
using Webzine.Entity;
|
|
using Webzine.Entity.Fixtures;
|
|
|
|
public class SeedDataSpotify
|
|
{
|
|
private readonly HttpClient httpClient;
|
|
private readonly SpotifySeederOptions options;
|
|
|
|
public SeedDataSpotify(HttpClient httpClient, IOptions<SpotifySeederOptions> optionsAccessor)
|
|
{
|
|
this.httpClient = httpClient;
|
|
this.options = optionsAccessor.Value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Générer les données de la base a l'aide des données de spotify.
|
|
/// </summary>
|
|
/// <param name="cancellationToken">Cancellation token.</param>
|
|
/// <returns>Jeu de données.</returns>
|
|
/// <exception cref="InvalidOperationException">Erreur de connexion a spotify.</exception>
|
|
public async Task<SeedDataSet> GenererJeuDeDonneesAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
// Verification des parametres pour l'acces a Spotify.
|
|
if (string.IsNullOrWhiteSpace(this.options.ClientId) || string.IsNullOrWhiteSpace(this.options.ClientSecret))
|
|
{
|
|
throw new InvalidOperationException("Renseignez SpotifySeeder:ClientId et SpotifySeeder:ClientSecret.");
|
|
}
|
|
|
|
var token = await this.GetTokenAsync(cancellationToken);
|
|
var styles = new Dictionary<string, Style>();
|
|
var artistes = new List<Artiste>();
|
|
var titres = new List<Titre>();
|
|
var commentaires = new List<Commentaire>();
|
|
var artistIds = new HashSet<string>();
|
|
int nextArtistId = 1;
|
|
int nextStyleId = 1;
|
|
int nextTitreId = 1;
|
|
int nextCommentaireId = 1;
|
|
|
|
foreach (var genre in this.options.Genres)
|
|
{
|
|
var artistesSpotify = await this.GetAsync<SpotifySearchArtistsResponseDto>(
|
|
$"https://api.spotify.com/v1/search?q={Uri.EscapeDataString($"genre:\"{genre}\"")}&type=artist&market={this.options.Market}&limit={this.options.ArtistsPerGenre}",
|
|
token,
|
|
cancellationToken);
|
|
|
|
foreach (var artisteSpotify in artistesSpotify?.Artists?.Items ??[])
|
|
{
|
|
if (string.IsNullOrWhiteSpace(artisteSpotify.Id) || !artistIds.Add(artisteSpotify.Id))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var stylesTitre = (artisteSpotify.Genres.Count > 0 ? artisteSpotify.Genres :[genre])
|
|
.Select(g => SpotifyMapper.GetOrCreateStyle(styles, g, ref nextStyleId))
|
|
.DistinctBy(s => s.IdStyle)
|
|
.ToList();
|
|
|
|
var artiste = SpotifyMapper.ToArtiste(artisteSpotify, stylesTitre, nextArtistId++);
|
|
artistes.Add(artiste);
|
|
|
|
var albums = await this.GetAsync<SpotifyAlbumsResponseDto>(
|
|
$"https://api.spotify.com/v1/artists/{artisteSpotify.Id}/albums?include_groups=album,single&market={this.options.Market}",
|
|
token,
|
|
cancellationToken);
|
|
|
|
foreach (var album in albums?.Items.GroupBy(a => a.Name).Select(g => g.First()) ??[])
|
|
{
|
|
var tracks = await this.GetAsync<SpotifyTracksResponseDto>(
|
|
$"https://api.spotify.com/v1/albums/{album.Id}/tracks?market={this.options.Market}&limit={Math.Clamp(this.options.TracksPerAlbum, 1, 10)}",
|
|
token,
|
|
cancellationToken);
|
|
|
|
foreach (var track in tracks?.Items ??[])
|
|
{
|
|
var titre = SpotifyMapper.ToTitre(track, album, artiste, stylesTitre, nextTitreId++);
|
|
|
|
var commentairesTitre = SeedDataLocal.GenererListeCommentaire(
|
|
titre,
|
|
0,
|
|
Math.Clamp(this.options.MaxCommentsPerTrack, 0, 10),
|
|
nextCommentaireId);
|
|
|
|
nextCommentaireId += commentairesTitre.Count;
|
|
|
|
titre.Commentaires.AddRange(commentairesTitre);
|
|
commentaires.AddRange(commentairesTitre);
|
|
titres.Add(titre);
|
|
artiste.Titres.Add(titre);
|
|
|
|
foreach (var style in titre.Styles)
|
|
{
|
|
style.Titres.Add(titre);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return new SeedDataSet
|
|
{
|
|
Artistes = artistes,
|
|
Styles = styles.Values.OrderBy(s => s.IdStyle).ToList(),
|
|
Titres = titres,
|
|
Commentaires = commentaires,
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recuperation du token d'access a Spotify.
|
|
/// </summary>
|
|
/// <param name="cancellationToken">Permet d'annuler la requete HTTP en cas de probleme.</param>
|
|
/// <returns>Le token d'acces a spotify.</returns>
|
|
/// <exception cref="InvalidOperationException">Le token spotify est introuvable.</exception>
|
|
private async Task<string> GetTokenAsync(CancellationToken cancellationToken)
|
|
{
|
|
using var request = new HttpRequestMessage(HttpMethod.Post, "https://accounts.spotify.com/api/token");
|
|
request.Content = new FormUrlEncodedContent(
|
|
[
|
|
new KeyValuePair<string, string>("grant_type", "client_credentials"),
|
|
]);
|
|
|
|
var basic = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{this.options.ClientId}:{this.options.ClientSecret}"));
|
|
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", basic);
|
|
|
|
using var response = await this.httpClient.SendAsync(request, cancellationToken);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var payload = await response.Content.ReadFromJsonAsync<SpotifyTokenResponseDto>(cancellationToken: cancellationToken);
|
|
return payload?.AccessToken ?? throw new InvalidOperationException("Token Spotify introuvable.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recuperation d'information depuis spotify, en formattant
|
|
/// la requete avec le Bearer Token.
|
|
/// </summary>
|
|
/// <typeparam name="T">DTOs Spotify.</typeparam>
|
|
/// <param name="url">URL Spotify.</param>
|
|
/// <param name="token">Token Bearer pour authorisation d'acces a l'api.</param>
|
|
/// <param name="cancellationToken">Permet d'annuler la requete.</param>
|
|
/// <returns>Reponse Spotify deserialiser.</returns>
|
|
private async Task<T?> GetAsync<T>(string url, string token, CancellationToken cancellationToken)
|
|
{
|
|
// Formattage de la requete HTTP avec le Bearer token.
|
|
using var request = new HttpRequestMessage(HttpMethod.Get, url);
|
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
|
|
using var response = await this.httpClient.SendAsync(request, cancellationToken);
|
|
response.EnsureSuccessStatusCode();
|
|
return await response.Content.ReadFromJsonAsync<T>(cancellationToken: cancellationToken);
|
|
}
|
|
} |