GetSimilarPlaylistsOrdered(Entities.Application.Playlist compared, List <Place> places, string spotifyToken)
        {
            var client = new HttpClient();


            OccurrenceSearcher occurrences = await FindPlaylistOccurences(compared, places, spotifyToken, client);

            var ponderedTags   = PonderOccurences(occurrences.Tags);
            var ponderedGenres = PonderOccurences(occurrences.Genres);

            var fmSucc  = double.TryParse(Configuration["FmPonderation"], out var fmCoeff);
            var spoSucc = double.TryParse(Configuration["SpoPonderation"], out var spoCoeff);
            // ordenar según getSimilitud según la ponderación que se quiera
            var result = places.Select(p =>
            {
                var similitude = GetSimilitude(ponderedTags[compared.Id], ponderedTags[p.MainPlaylist.Id])
                                 * (fmSucc ? fmCoeff : 0.5)
                                 + GetSimilitude(ponderedGenres[compared.Id], ponderedGenres[p.MainPlaylist.Id])
                                 * (spoSucc ? spoCoeff : 0.5);
                var res        = new ComparedPlace(p);
                res.Similitude = similitude;
                return(res);
            }).OrderByDescending(c => c.Similitude);

            return(result);
        }
        private async Task <OccurrenceSearcher> FindPlaylistOccurences(Entities.Application.Playlist compared,
                                                                       List <Place> places, string spotifyToken, HttpClient client)
        {
            var occurrences = new OccurrenceSearcher();

            await places.ToAsyncEnumerable().ForEachAwaitAsync(async(Place place) =>
            {
                var header = await _spotify.GetPlaylistHeader(client, spotifyToken, place.MainPlaylist.Id);
                if (header != null)
                {
                    if (header.Snapshot_id == place.MainPlaylist.SnapshotVersion &&
                        place.MainPlaylist.Tags != null &&
                        place.MainPlaylist.Tags.Any() &&
                        place.MainPlaylist.Genres != null &&
                        place.MainPlaylist.Genres.Any())
                    {
                        occurrences.UpdateTags(place.MainPlaylist.Tags, place.MainPlaylist.Id);
                        occurrences.UpdateGenres(place.MainPlaylist.Genres, place.MainPlaylist.Id);
                    }
                    else
                    {
                        var playlistSongs =
                            (await _spotify.GetSongsFromPlaylist(client, spotifyToken, place.MainPlaylist.Id))
                            .Items.Select(s => new Entities.Application.Song(s)).ToList();

                        await GetTagsAndGenresFromSongs(spotifyToken, place.MainPlaylist.Id, playlistSongs, occurrences);

                        place.MainPlaylist.SnapshotVersion = header.Snapshot_id;
                        place.MainPlaylist.Songs           = playlistSongs;
                        place.MainPlaylist.Tags            = occurrences.GetTags(place.MainPlaylist.Id);
                        place.MainPlaylist.Genres          = occurrences.GetGenres(place.MainPlaylist.Id);
                    }
                }
            });

            await GetTagsAndGenresFromSongs(spotifyToken, compared.Id, compared.Songs, occurrences);

            compared.Tags   = occurrences.GetTags(compared.Id);
            compared.Genres = occurrences.GetGenres(compared.Id);

            return(occurrences);
        }
        private async Task GetTagsAndGenresFromSongs(string token, string playlistId, List <Entities.Application.Song> songs, OccurrenceSearcher occurrences)
        {
            var client = new HttpClient();
            var lastFmTagOccurrenceConc    = new ConcurrentDictionary <string, int>();
            var spotifyGenreOccurrenceConc = new ConcurrentDictionary <string, int>();
            await songs.ToAsyncEnumerable().ForEachAwaitAsync(async(song) =>
            {
                var fmSuccess = false;
                while (!fmSuccess)
                {
                    try
                    {
                        var lastFmTags = await lastFmService.GetTrackTags(client, song.Name, song.Artists[0]?.Name);
                        if (lastFmTags != null && lastFmTags.Toptags != null && lastFmTags.Toptags.Tag != null)
                        {
                            lastFmTags.Toptags.Tag.Sort(new TagComparer());

                            lastFmTags.Toptags.Tag.Take(5).ToList().ForEach(t =>
                            {
                                lastFmTagOccurrenceConc.AddOrUpdate(t.Name, 1, (k, old) => old + 1);
                            });
                        }
                        fmSuccess = true;
                    }
                    catch (TaskCanceledException) { }
                }
                var artists = song.Artists.Select(a => a.Id).ToList();
                if (artists.Any())
                {
                    var newArtists = artists.Where(a => !occurrences.ArtistExists(a)).ToList();

                    if (newArtists.Any())
                    {
                        newArtists.ForEach(a => occurrences.UpdateArtistGenres(new List <string>(), a));
                        var stringArtists  = newArtists.Aggregate((a, b) => a + "," + b);
                        var spotifySuccess = false;
                        while (!spotifySuccess)
                        {
                            try
                            {
                                var spotifyTags = await _spotify.GetArtists(client, token, stringArtists);
                                if (spotifyTags != null)
                                {
                                    spotifyTags.ForEach(a => occurrences.UpdateArtistGenres(a.Genres.ToList(), a.Id));
                                    spotifySuccess = true;
                                }
                            }
                            catch (TaskCanceledException) { }
                        }
                    }

                    artists.ForEach(s =>
                    {
                        occurrences.GetArtistGenres(s).ForEach(g =>
                        {
                            // Add Genre occurrence
                            spotifyGenreOccurrenceConc.AddOrUpdate(g, 1, (k, l) => l + 1);
                        });
                    });
                }
            });

            occurrences.UpdateTags(new Dictionary <string, int>(lastFmTagOccurrenceConc), playlistId);
            occurrences.UpdateGenres(new Dictionary <string, int>(spotifyGenreOccurrenceConc), playlistId);
        }