using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MoreLinq; using NLog; using Sony.Filtr.ApolloAPI; using Sony.Filtr.Contracts.Abstractions; using Sony.Filtr.Contracts.Definitions; using Sony.Filtr.Contracts.Entities; using Sony.Filtr.Core.PromotedTracks; using Sony.Filtr.Core.Settings; using Sony.Filtr.DeezerAPI; using Sony.Filtr.DeezerAPI.Model; using Sony.Filtr.ErrorLogging; using Sony.Filtr.PlaylistGeneration; using Sony.Filtr.Utility.Extensions; using Artist = Sony.Filtr.Contracts.Entities.Artist; using PlaylistTrackItem = Sony.Filtr.SpotifyWebAPI.Model.PlaylistTrackItem; using Track = Sony.Filtr.Contracts.Entities.Track; using Sony.Filtr.VendorToSpotify; namespace Sony.Filtr.Tasks.Tasks.PublicApi { public class PromotedTracksImport : IScheduledTask { private readonly SettingsManager _settingsManager; private readonly PromotedTracksManager _promotedTracksManager; private readonly PlaylistGenerationManager _playlistGenerationManager; private readonly IApplicationInstanceManager _applicationInstanceManager; private readonly ErrorLoggingManager _errorLoggingManager; private readonly DeezerApi _deezerApi; private readonly IApolloWebApi _vendorApi; private static int _numberOfTrackGenreFails; private readonly Logger _logger; public PromotedTracksImport(IApolloWebApi vendorApi, SettingsManager settingsManager, PromotedTracksManager promotedTracksManager, PlaylistGenerationManager playlistGenerationManager, IApplicationInstanceManager applicationInstanceManager, ErrorLoggingManager errorLoggingManager, DeezerApi deezerApi) { _vendorApi = vendorApi; _settingsManager = settingsManager; _promotedTracksManager = promotedTracksManager; _playlistGenerationManager = playlistGenerationManager; _applicationInstanceManager = applicationInstanceManager; _errorLoggingManager = errorLoggingManager; _deezerApi = deezerApi; _logger = NLog.LogManager.GetLogger("PromotedTracksImport"); } public async Task ExecuteAsync(Guid scheduledTaskLogId) { var taskLog = new ScheduledTaskLog(); var dataLog = new ScheduledTaskDataLog("SpotifyPromotedTrack", DateTimeOffset.UtcNow, scheduledTaskLogId); _logger.Debug("Start promoted tracks update"); List allPromotedTracks = new List(); foreach (var app in _applicationInstanceManager.GetApplications()) { try { List promotedTracks = new List(); var spotifyPromotedTracks = await GetSpotifyPromotedTracksAsync(app); promotedTracks.AddRange(spotifyPromotedTracks); var deezerPromotedTracks = await GetDeezerPromotedTracksAsync(app); promotedTracks.AddRange(deezerPromotedTracks); await _promotedTracksManager.SetPromotedTracksAsync(app, promotedTracks); allPromotedTracks.AddRange(promotedTracks); } catch (Exception ex) { _errorLoggingManager.LogError(ex); _logger.Error(ex); } } _logger.Debug("Failed to get any genres for " + _numberOfTrackGenreFails + " tracks."); _logger.Debug("Personas updated"); var uniqueSpotifyTracks = allPromotedTracks.Select(p => p.ExtendedTrack).Where(p => p?.SpotifyLink?.Uri != null).DistinctBy(p => p.SpotifyLink.Uri).Count(); var uniqueDeezerTracks = allPromotedTracks.Select(p => p.ExtendedTrack).Where(p => p?.DeezerId != null).DistinctBy(p => p.DeezerId).Count(); dataLog.Finished = DateTimeOffset.UtcNow; dataLog.Rows = uniqueDeezerTracks + uniqueSpotifyTracks; taskLog.DataLogs.Add(dataLog); return taskLog; } private async Task> GetDeezerPromotedTracksAsync(Application app) { List promotedTracks = new List(); var playlistId = _settingsManager.GetIntSetting("DeezerPromotedTracksPlaylist", app); if (playlistId > 0) { _logger.Debug("Beginning deezer promoted tracks sync for " + app.Name); _logger.Debug("Will fetch playlist:" + playlistId); var deezerPlaylistTracks = await _deezerApi.GetAllPlaylistTracksAsync(playlistId); if (deezerPlaylistTracks != null) { _logger.Debug("Fetched deezer playlist"); _logger.Debug("playlist contains " + deezerPlaylistTracks.Count + " tracks"); var fullDeezerTracks = await _deezerApi.GetMultipleTracksAsync(deezerPlaylistTracks.Select(t => long.Parse(t.id))); foreach (var track in fullDeezerTracks) { try { var promotedTrack = await GenerateDeezerPromotedTrackAsync(app, track); promotedTracks.Add(promotedTrack); } catch (Exception ex) { _errorLoggingManager.LogError(ex); _logger.Error(ex, "Could not generate promoted track for " + track.title); } } } else { _logger.Warn("Could not get playlist for " + playlistId); } } return promotedTracks; } private async Task GenerateDeezerPromotedTrackAsync(Application app, TrackResponse track) { var artist = track.artist?.name; _logger.Debug("Fetching info for: " + artist + " - " + track.title); var promotedTrack = new PromotedTrack { ServiceType = ServiceType.Deezer, ApplicationId = app.ID, ExtendedTrack = new ExtendedTrack() { DeezerId = long.Parse(track.id), Duration = int.Parse(track.duration), ISRC = track.isrc, DeezerIds = new List() { long.Parse(track.id)}, Tempo = track.bpm, Title = track.title, ArtistName = track.artist?.name, Territories = track.available_countries, } }; var localTrack = new Track(artist, track.title); var genres = (await _playlistGenerationManager.GetGenresAsync(app, localTrack)).ToList(); if (!genres.Any()) { _numberOfTrackGenreFails++; genres = (await _playlistGenerationManager.GetGenresAsync(app, new Artist(artist))).ToList(); } promotedTrack.Tags = genres.Select(g => new Tag() { Name = g.Genre, Score = g.Score }).ToList(); return promotedTrack; } private async Task> GetSpotifyPromotedTracksAsync(Application app) { List promotedTracks = new List(); var playlistUrl = _settingsManager.GetStringSetting("PromotedTracksPlaylist", app); if (!string.IsNullOrWhiteSpace(playlistUrl)) { _logger.Debug("Beginning promoted tracks sync for " + app.Name); _logger.Debug("Will fetch playlist:" + playlistUrl); var spotifyLink = new SpotifyLink(playlistUrl); //TODO: Specify fields var playlistTracks = (await _vendorApi.GetAllPlaylistTracksByIdAsync(spotifyLink.ExtractPlaylistID())).ToSpotify(); if (playlistTracks != null) { playlistTracks = playlistTracks.Where(t => t.track != null).ToList(); _logger.Debug("Fetched playlist"); _logger.Debug("playlist contains " + playlistTracks.Count() + " tracks"); var localTracks = playlistTracks .DistinctBy(k => k.track.uri) .Select(t => new Track(t.track.name, t.track.name) { SpotifyLink = new SpotifyLink(t.track.uri, urlDecode:false), Territories = new List() }) .ToList(); var localTracksDic = localTracks.ToDictionary(k => k.SpotifyLink.Uri, v => v); var extendedTracks = await _playlistGenerationManager.GetExtendedTracksAsync(localTracks); var extendedTracksDic = extendedTracks.ToDictionary(k => k.SpotifyLink.Uri, v => v); foreach (var track in playlistTracks) { try { var localTrack = localTracksDic.GetValueOrDefault(track.track.uri); var extendedTrack = extendedTracksDic.GetValueOrDefault(track.track.uri); var promotedTrack = await GenerateSpotifyPromotedTrackAsync(app, track, localTrack, extendedTrack); promotedTracks.Add(promotedTrack); } catch (Exception ex) { _errorLoggingManager.LogError(ex); _logger.Error(ex, "Could not generate promoted track for " + track.track.name); } } } else { _logger.Warn("Could not get playlist for " + playlistUrl); } } return promotedTracks; } private async Task GenerateSpotifyPromotedTrackAsync(Application app, PlaylistTrackItem track, Track localTrack, ExtendedTrack extendedTrack) { var artist = track.track.artists.First(); var personaName = artist.name + " - " + track.track.name; _logger.Debug("Fetching info for: " + personaName); var promotedTrack = new PromotedTrack { ServiceType = ServiceType.Spotify, ApplicationId = app.ID }; var genres = (await _playlistGenerationManager.GetGenresAsync(app, localTrack)).ToList(); if (!genres.Any()) { _numberOfTrackGenreFails++; genres = (await _playlistGenerationManager.GetGenresAsync(app, new Artist(artist.name))).ToList(); } if (extendedTrack != null) promotedTrack.ExtendedTrack = extendedTrack; else promotedTrack.ExtendedTrack = new ExtendedTrack() { SpotifyLink = new SpotifyLink(track.track.uri) }; promotedTrack.Tags = genres.Select(g=> new Tag() { Name = g.Genre, Score = g.Score}).ToList(); return promotedTrack; } } }