using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Nancy; using Sony.Filtr.AdminAPI.Config; using Sony.Filtr.AdminAPI.Utility; using Sony.Filtr.AdminAPI.ViewModels.Graph; using Sony.Filtr.Contracts.Abstractions; using Sony.Filtr.Contracts.Entities; using Sony.Filtr.Playlists.Spotify; using Sony.Filtr.Playlists.Spotify.Model.History; using Sony.Filtr.SpotifyWebAPI; using Sony.Filtr.Utility; using Sony.Filtr.Utility.Extensions; namespace Sony.Filtr.AdminAPI.Modules.SpotifySpecific { public class SpotifyPlaylistTrackGraphModule : BaseModule { public SpotifyPlaylistTrackGraphModule(IApplicationInstanceManager applicationInstanceManager, SpotifyPlaylistHistoricTrackListManager historicTrackListManager, SpotifyPlaylistManager spotifyPlaylistManager, SpotifyWebApi spotifyWebApi) : base(applicationInstanceManager) { Get["PlaylistTrackGraphPosition", "/playlistTrackGraph/position", true] = async (parameters, cx) => { string playlistId = Request.GetRequiredPlaylistId(); string trackUri = (string)Request.Query.trackUri; string isrc = (string)Request.Query.isrc; DateTime startDate = Maybe.ToDateTimeOrFallback((string)Request.Query.startDate, DateTime.Today.AddDays(-30)); DateTime endDate = Maybe.ToDateTimeOrFallback((string)Request.Query.endDate, DateTime.Today); if (trackUri != null) { var trackId = new SpotifyLink(trackUri).ExtractTrackID(); var trackIdList = new List { trackId }; var isrcResponse = await spotifyPlaylistManager.GetIsrcFromTrackIdAsync(trackIdList); isrc = isrcResponse.GetValueOrDefault(trackId); if (string.IsNullOrWhiteSpace(isrc)) { var spotifyTrackResponse = await spotifyWebApi.GetAllTracksAsync(trackIdList); isrc = spotifyTrackResponse?.FirstOrDefault()?.external_ids?.isrc; } } if (string.IsNullOrWhiteSpace(isrc)) { throw new NancyStatusException(HttpStatusCode.NotFound, "Could not get ISRC for track"); } var positions = await historicTrackListManager.GetHistoricTrackPositionsAsync(playlistId, isrc, startDate, endDate); // Adds or replaces current tracklist position to avoid using "old" data in latest entry. await ApplyCurrentTracklistPositionAsync(spotifyPlaylistManager, startDate, endDate, playlistId, isrc, positions); var viewModel = new GraphViewModel { Series = new List() { new PlaylistTrackPositionSeriesViewModel() { Entries = positions.Select(e => new TrackPositionGraphEntry() { Date = e.Date, Position = e.Position+1, //We store position as zero-indexed but expose it as one-indexed, TrackCount = e.TotalTracks, }).OrderBy(e => e.Date).ToList() } } }; return Response.AsJson(viewModel); }; } private async Task ApplyCurrentTracklistPositionAsync(SpotifyPlaylistManager spotifyPlaylistManager, DateTime startDate, DateTime endDate, string playlistId, string isrc, List positions) { var today = DateTime.UtcNow.Date; if (today >= startDate && today <= endDate) { var currentTracks = await spotifyPlaylistManager.GetTrackListWithDataByIdAsync(playlistId); var specificTrack = currentTracks.Where(t => isrc.Equals(t.ISRC, StringComparison.InvariantCultureIgnoreCase)).ToList(); if (specificTrack.Any()) { var currentPosition = specificTrack.First().Position; var todaysPosition = positions.FirstOrDefault(p => p.Date.Date == today); if (todaysPosition != null) { todaysPosition.Position = currentPosition; //todaysPosition.Date = DateTime.UtcNow; //Would be nice if we had real date when we fetched playlist tracklist. } else { positions.Add(new HistoricTrackPosition() { Date = DateTime.UtcNow, Position = currentPosition, TotalTracks = currentTracks.Count() }); } } } } public class PlaylistTrackPositionSeriesViewModel { public List Entries { get; set; } } public class TrackPositionGraphEntry { public DateTime Date { get; set; } public int Position { get; set; } public int TrackCount { get; set; } } } }