using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using MoreLinq; using Sony.Filtr.Contracts.Definitions; using Sony.Filtr.Contracts.Entities; using Sony.Filtr.PlaylistGeneration.MusicInfoStore.LastFm; using Sony.Filtr.PlaylistSynchronization; using Sony.Filtr.SpotifyWebAPI; using Sony.Filtr.SpotifyWebAPI.Model; namespace Sony.Filtr.Worker.Onetime { public class ArtistReleasesInYear { private readonly SpotifyWebApi _spotifyWebApi; private readonly ServiceAccountManager _serviceAccountManager; private readonly LastFmApi _lastFmApi; public ArtistReleasesInYear(SpotifyWebApi spotifyWebApi, ServiceAccountManager serviceAccountManager) { _spotifyWebApi = spotifyWebApi; _serviceAccountManager = serviceAccountManager; } public async Task ExecuteTaskAsync() { const string spotifyUsername = "viruzi"; const string lastFmUsername = "viruzi"; var albumPlaylistLink = new SpotifyLink("spotify:user:viruzi:playlist:7lOyRmPBP2BRxSfUXaEP4j"); var singlePlaylistLink = new SpotifyLink("spotify:user:viruzi:playlist:4PgGYHd3tyz8k3QU9hUfLG"); var serviceAccount = _serviceAccountManager.GetServiceAccount(ServiceType.Spotify, spotifyUsername); var spotifyAuthApi = _spotifyWebApi.GetAuthenticatedSession(serviceAccount); await ClearPlaylistsAsync(spotifyAuthApi, albumPlaylistLink); await ClearPlaylistsAsync(spotifyAuthApi, singlePlaylistLink); const string market = "SE"; var albumPlaylistTracks = await _spotifyWebApi.GetAllPlaylistTracksAsync(albumPlaylistLink.ExtractSpotifyPlaylistUserName(), albumPlaylistLink.ExtractPlaylistID(), market: market); var albumPlaylistTracksDic = albumPlaylistTracks.Select(k => k.track.uri).ToHashSet(); var singlePlaylistTracks = await _spotifyWebApi.GetAllPlaylistTracksAsync(singlePlaylistLink.ExtractSpotifyPlaylistUserName(), singlePlaylistLink.ExtractPlaylistID(), market: market); var singlePlaylistTracksDic = singlePlaylistTracks.Select(k => k.track.uri).ToHashSet(); await ClearDuplicatesAsync(spotifyAuthApi, albumPlaylistLink, albumPlaylistTracks); await ClearDuplicatesAsync(spotifyAuthApi, singlePlaylistLink, singlePlaylistTracks); var mostPopularArtistsOnSpotify = await GetMyMostPopularArtistIdsOnSpotify(spotifyAuthApi); var mostPopularArtistsIdOnLastFm = await GetMyMostPopularArtistsIdFromLastFm(lastFmUsername); var mostPopularArtists = mostPopularArtistsOnSpotify.Take(400).Union(mostPopularArtistsIdOnLastFm.Take(500)).Where(a => !string.IsNullOrWhiteSpace(a)).Distinct(); List albumTracksToAdd = new List(); List singleTracksToAdd = new List(); foreach (var artist in mostPopularArtists) { var albums = await _spotifyWebApi.GetAllArtistAlbumsAsync(artist, market: market); var albumIds = albums.Where(a => !string.IsNullOrWhiteSpace(a.id) && a.album_type.HasValue && (a.album_type == AlbumType.single || a.album_type == AlbumType.album)).Select(a => a.id); var albumInfos = await _spotifyWebApi.GetAllAlbumInfoAsync(albumIds, market: market); var recentAlbums = albumInfos.Where(a => a.release_date != null && a.release_date.StartsWith("2016")).ToList(); Console.WriteLine("Found {0} recent releases by {1}.", recentAlbums.Count(), artist); foreach(var album in recentAlbums) { if (album.album_type == AlbumType.album && !IsSoundtrack(album) && !IsCompilation(artist, album)) { var tracksToAdd = album.tracks.items.Where(track => !albumPlaylistTracksDic.Contains(track.uri)).Select(track => track.uri).ToList(); if (tracksToAdd.Any()) albumTracksToAdd.AddRange(tracksToAdd); } else if (album.album_type == AlbumType.single) { var tracksToAdd = album.tracks.items.Where(track => !singlePlaylistTracksDic.Contains(track.uri)).Select(track => track.uri).ToList(); if (tracksToAdd.Any()) singleTracksToAdd.AddRange(tracksToAdd); } } } if (albumTracksToAdd.Any()) { await spotifyAuthApi.AddManyTrackAsync(albumPlaylistLink.ExtractSpotifyPlaylistUserName(), albumPlaylistLink.ExtractPlaylistID(), albumTracksToAdd); } if (singleTracksToAdd.Any()) { await spotifyAuthApi.AddManyTrackAsync(singlePlaylistLink.ExtractSpotifyPlaylistUserName(), singlePlaylistLink.ExtractPlaylistID(), singleTracksToAdd); } } private async Task ClearPlaylistsAsync(AuthenticatedSpotifyWebApi spotifyAuthApi, SpotifyLink playlist) { var userId = playlist.ExtractSpotifyPlaylistUserName(); var playlistId = playlist.ExtractPlaylistID(); var existingTracks = await _spotifyWebApi.GetAllPlaylistTracksAsync(userId, playlistId); foreach(var tracksBatch in existingTracks.Batch(100)) { await spotifyAuthApi.DeletePlaylistTracksAsync(userId, playlistId, tracksBatch.Select(t => t.track.id)); } } private async Task ClearDuplicatesAsync(AuthenticatedSpotifyWebApi spotifyAuthApi, SpotifyLink albumPlaylistLink, List albumPlaylistTracks) { List trackInPositions = new List(); var trackLookup = albumPlaylistTracks.Select(t => t.track.uri).ToHashSet(); var trackGroups = albumPlaylistTracks.Where(t => trackLookup.Contains(t.track.uri)).GroupBy(g => g.track.uri); foreach (var duplicateTrackGroup in trackGroups.Where(c => c.Count() > 1)) { var orderedDuplicateTracks = duplicateTrackGroup.OrderByDescending(r => r.added_at); trackInPositions.Add(new TrackInPosition() { uri = orderedDuplicateTracks.First().track.uri, positions = orderedDuplicateTracks.Skip(1).Select(ti => albumPlaylistTracks.IndexOf(ti)).ToList() }); } await spotifyAuthApi.DeletePlaylistTracksInPositionAsync(albumPlaylistLink.ExtractSpotifyPlaylistUserName(), albumPlaylistLink.ExtractPlaylistID(), trackInPositions, null); } private async Task> GetMyMostPopularArtistIdsOnSpotify(AuthenticatedSpotifyWebApi spotifyAuthApi) { var shortTermArtists = await spotifyAuthApi.GetMyTopArtists(AuthenticatedSpotifyWebApi.MyTopTimeRange.short_term, limit: 50); var mediumTermArtists = await spotifyAuthApi.GetMyTopArtists(AuthenticatedSpotifyWebApi.MyTopTimeRange.medium_term, limit: 50); var longTermArtists = await spotifyAuthApi.GetMyTopArtists(AuthenticatedSpotifyWebApi.MyTopTimeRange.long_term, limit: 50); return shortTermArtists.items.Union(mediumTermArtists.items).Union(longTermArtists.items).Select(a => a.id).Distinct().ToList(); //var playlists = await _spotifyWebApi.GetAllPublicPlaylistsAsync("viruzi"); //List allPlaylistTracks = new List(); //foreach(var playlist in playlists) //{ // var tracks = await _spotifyWebApi.GetAllPlaylistTracksAsync(playlist.owner.id, playlist.id); // allPlaylistTracks.AddRange(tracks); //} //var mostPopularArtistsOnSpotify = allPlaylistTracks.SelectMany(a => a.track.artists).GroupBy(k => k.id) // .Where(c => c.Count() > 10).OrderByDescending(c => c.Count()).Select(c => c.Key); //return mostPopularArtistsOnSpotify; } private async Task> GetMyMostPopularArtistsIdFromLastFm(string lastFmUsername) { var lastFmApi = new LastFmApi("***REMOVED***", "***REMOVED***", new HttpClient()); List mostPopularArtistsNameOnLastFm = new List(); var lastFmPopularArtist = await lastFmApi.GetTopArtistsForUserAsync(lastFmUsername, limit: 100); mostPopularArtistsNameOnLastFm.AddRange(lastFmPopularArtist.artists.artist.Select(a => a.name)); //var morePages = lastFmPopularArtist.artists.Attr.totalPages ?? 0; //if (morePages > 1) //{ // foreach(var morePage in Enumerable.Range(1, morePages)) // { // var moreLastFmPopularArtist = await lastFmApi.GetTopArtistsForUserAsync("VirUZI", limit: 500, page: morePage); // mostPopularArtistsNameOnLastFm.AddRange(moreLastFmPopularArtist.artists.artist.Select(a => a.name)); // } //} List mostPopularArtistsIdOnLastFm = new List(); foreach (var lastFmArtist in lastFmPopularArtist.artists.artist) { var artistName = lastFmArtist.name; Console.WriteLine("Doing lookup of {0}", artistName); try { var spotifyArtistResult = await _spotifyWebApi.SearchArtistsAsync("artist:" + artistName); var artistId = spotifyArtistResult?.artists?.items?.FirstOrDefault()?.id; if (!string.IsNullOrWhiteSpace(artistId)) { Console.WriteLine("Found artist {0} for {1}", artistId, artistName); mostPopularArtistsIdOnLastFm.Add(artistId); } } catch(Exception ex) { Console.WriteLine("Exception for lookup:" + ex.ToString()); } } return mostPopularArtistsIdOnLastFm; } private bool IsCompilation(string artist, FullAlbumItem album) { var tracksWithArtist = album.tracks.items.Count(a => a.artists.Select(ai => ai.id).Contains(artist)); var totalTracks = album.tracks.items.Count; var percentage = (tracksWithArtist / (totalTracks*1.0))*100; if (percentage < 70) { Console.WriteLine("{0} by {1} looks like compilation!", album.name, album.artists.First().name); return true; } return false; } private bool IsSoundtrack(FullAlbumItem album) { var isSoundtrack = Contains(album.name, "soundtrack") || Contains(album.name, " OST"); if (isSoundtrack) { Console.WriteLine("{0} by {1} looks like compilation!", album.name, album.artists.First().name); } return isSoundtrack; } private bool Contains(string text, string searchTerm) { return text.IndexOf(searchTerm, StringComparison.InvariantCultureIgnoreCase) >= 0; } } }