using Sony.Filtr.Playlists.Models; using Sony.Filtr.Playlists.Spotify; using Sony.Filtr.SpotifyWebAPI.Model; using Sony.Filtr.Utility.Extensions; using System; using System.Collections.Generic; using System.Data.SqlTypes; using System.Linq; using System.Threading.Tasks; using Track = Sony.Filtr.SpotifyWebAPI.Model.Track; using Sony.Filtr.ApolloAPI.Models; namespace Sony.Filtr.Tasks.Helpers { public class UpdatePlaylistsHelper { private readonly SpotifyPlaylistHistoricTrackListManager _historicTrackListManager; public UpdatePlaylistsHelper(SpotifyPlaylistHistoricTrackListManager historicTrackListManager) { _historicTrackListManager = historicTrackListManager; } public async Task SetEarliestAddedDateAsync(IEnumerable spotifyApiTracks, IEnumerable dbTracks, string playlistId, string ownerUsername) { if (ownerUsername.Equals("spotifycharts", StringComparison.InvariantCultureIgnoreCase)) { //These playlists don't have added date so we check our historic playlists to get earliest added date await SetEarliestAddedDateFor_SpotifyChart_UserAsync(spotifyApiTracks, playlistId); } else { SetEarliestAddedDateCommon(spotifyApiTracks, dbTracks); } FixIsrcs(spotifyApiTracks); } private void SetEarliestAddedDateCommon(IEnumerable spotifyApiTracks, IEnumerable dbTracks) { Func, Dictionary> buildEarliestAddedDateMapBy = groupBy => dbTracks .Where(t => t.EarliestAdded.HasValue) .Where(t => groupBy(t) != null) .GroupBy(groupBy) .ToDictionary(k => k.Key, v => v.Min(p => p.EarliestAdded.Value)); Dictionary dbTracksEarliestAddedMapByIsrc = buildEarliestAddedDateMapBy(t => t.Track.Isrc); Dictionary dbTracksEarliestAddedMapByTrackId = buildEarliestAddedDateMapBy(t => t.Track.Id); Func getTrackEarliestAddedDate = track => { Func getSafeEarliestAdded = dt => (!dt.HasValue || dt.Value == DateTime.MinValue || dt.Value == SqlDateTime.MinValue) ? track.Added : dt; if (track.Track.Isrc != null && dbTracksEarliestAddedMapByIsrc.ContainsKey(track.Track.Isrc)) { return getSafeEarliestAdded(dbTracksEarliestAddedMapByIsrc[track.Track.Isrc]); } if (dbTracksEarliestAddedMapByTrackId.ContainsKey(track.Track.Id)) { return getSafeEarliestAdded(dbTracksEarliestAddedMapByTrackId[track.Track.Id]); } return track.Added; }; spotifyApiTracks.ForEachMy(apiTrack => apiTrack.EarliestAdded = getTrackEarliestAddedDate(apiTrack)); } private async Task SetEarliestAddedDateFor_SpotifyChart_UserAsync(IEnumerable spotifyApiTracks, string playlistId) { var isrcs = spotifyApiTracks.Select(p => p.Track.Isrc).Where(p => !string.IsNullOrWhiteSpace(p)).Distinct().ToList(); var historicEarliestAddedIsrc = await _historicTrackListManager.GetEarliestAddedDateAsync(playlistId, isrcs); foreach (var spotifyTrack in spotifyApiTracks.Where(p => !string.IsNullOrWhiteSpace(p.Track.Isrc))) { var earliestAdded = historicEarliestAddedIsrc.GetValueOrDefault(spotifyTrack.Track.Isrc); if (earliestAdded != DateTime.MinValue && earliestAdded != SqlDateTime.MinValue) { spotifyTrack.EarliestAdded = earliestAdded; } } } private void FixIsrcs(IEnumerable tracks) { tracks .Where(t => t.Track.Isrc != null) .ForEachMy(track => track.Track.Isrc = track.Track.Isrc.Replace("-", String.Empty)); } public bool IsTrackListChanged(IEnumerable existingTracklist, IEnumerable tracks) { if (existingTracklist.Count() != tracks.Count()) { return true; } Func areEqual = GetUpdatePlaylistTrackEqualFunc(); for (int playlistIndex = 0; playlistIndex < existingTracklist.Count(); playlistIndex++) { var oldTrack = existingTracklist.ElementAt(playlistIndex); var newTrack = tracks.ElementAt(playlistIndex); if (areEqual(oldTrack, newTrack) == false) { return true; } } return false; } public static Func GetUpdatePlaylistTrackEqualFunc() { return (x, y) => { if (x.Track.Id != y.Track.Id || x.Added != y.Added || x.EarliestAdded != y.EarliestAdded) { return false; } return true; }; } public DateTime? CalculateTrackLatestAdded(IEnumerable tracks) { DateTime? trackLatestAdded = null; var addedDates = tracks.Where(t => t.Added.HasValue && t.Added > DateTime.MinValue && t.Added.Value > SqlDateTime.MinValue.Value).Select(t => t.Added).ToList(); if (addedDates.Any()) { trackLatestAdded = addedDates.Max(); } return trackLatestAdded; } public UpdatePlaylistTrack BuildSpotifyPlaylistTrack(SpotifyPlaylistTrackItem t, int index) { var spotifyTrack = new UpdatePlaylistTrack() { Track = BuildSpotifyPlaylistTrack(t.track), PlaylistIndex = index, Added = t.added_at, }; return spotifyTrack; } public GeneralSpotifyTrack BuildSpotifyPlaylistTrack(SpotifyTrack t) { return new GeneralSpotifyTrack { Id = t.id, Name = t.name, Duration = t.duration_ms / 1000, Artists = t.artists.Select(a => new UpdatePlaylistArtist() { Name = a.name, Id = a.id }).ToList(), Isrc = t.external_ids.isrc, Popularity = t.popularity, AlbumIndex = t.track_number, Album = new UpdatePlaylistAlbum() { Id = t.album.id, Name = t.album.name, AlbumType = t.album.album_type, }, }; } public UpdatePlaylistTrack BuildSpotifyPlaylistTrack(PlaylistTrackItem t, int index) { var spotifyTrack = new UpdatePlaylistTrack() { Track = BuildSpotifyPlaylistTrack(t.track), PlaylistIndex = index, Added = t.added_at, }; return spotifyTrack; } public GeneralSpotifyTrack BuildSpotifyPlaylistTrack(Track t) { return new GeneralSpotifyTrack { Id = t.id, Name = t.name, Duration = t.duration_ms / 1000, Artists = t.artists == null ? new List() : t.artists.Select(a => new UpdatePlaylistArtist() { Name = a.name, Id = a.id }).ToList(), Isrc = t.external_ids.isrc, Popularity = t.popularity, AlbumIndex = t.track_number, Album = new UpdatePlaylistAlbum() { Id = t.album.id, Name = t.album.name, AlbumType = t.album.album_type, }, }; } public bool ShouldCheckForPersonalizedPlaylist(Contracts.Entities.SpotifyPlaylist playlist) { return ShouldCheckForPersonalizedPlaylist(playlist.User, playlist.Name); } public bool ShouldCheckForPersonalizedPlaylist(string user, string playlistName) { //only spotify administered playlists currently feature personalization //if (user != null && user.Equals("spotify", StringComparison.InvariantCultureIgnoreCase)) //{ // if (playlistName != null && (playlistName.StartsWith("This is:", StringComparison.InvariantCultureIgnoreCase) || playlistName.StartsWith("This is ", StringComparison.InvariantCultureIgnoreCase) || playlistName.StartsWith("Inspired by ", StringComparison.InvariantCultureIgnoreCase) || playlistName.EndsWith(" Radio", StringComparison.InvariantCultureIgnoreCase))) // return false; // //Check playlistId-prefix 37i9dQZ? // return true; //} //return false; Func playlistNameStartsWith = substring => playlistName.StartsWith(substring, StringComparison.InvariantCultureIgnoreCase); Func playlistNameEndsWith = substring => playlistName.EndsWith(substring, StringComparison.InvariantCultureIgnoreCase); Func userNameIsSpotify = () => user != null && user.Equals("spotify", StringComparison.InvariantCultureIgnoreCase); return userNameIsSpotify() && (playlistName != null) && !playlistNameStartsWith("This is:") && !playlistNameStartsWith("This is ") && !playlistNameStartsWith("Inspired by ") && !playlistNameEndsWith(" Radio"); } } }