using Nancy; using Nancy.ModelBinding; using Sony.Filtr.AdminAPI.ViewModels.NewMusicFriday; using Sony.Filtr.ApolloAPI; using Sony.Filtr.Contracts.Abstractions; using Sony.Filtr.Contracts.Definitions; using Sony.Filtr.Contracts.Entities; using Sony.Filtr.Core.SonyMusic; using Sony.Filtr.NewMusicFriday; using Sony.Filtr.Playlists.Spotify; using Sony.Filtr.Playlists.Spotify.Model; using Sony.Filtr.SpotifyWebAPI; using Sony.Filtr.Utility.Extensions; using Sony.Filtr.Utility.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Sony.Filtr.AdminAPI.Modules { public class NewMusicFridayModule : BaseModule { private readonly NewMusicFridayManager _nmfManager; private readonly NewMusicFridayFactory _nmfFactory; private readonly SpotifyWebApi _spotifyWebApi; private readonly SpotifyPlaylistManager _spotifyPlaylistManager; private readonly SonyMusicManager _sonyMusicManager; private readonly SpotifyTrackManager _spotifyTrackManager; private readonly IApolloWebApi _apolloWebApi; public NewMusicFridayModule(IApplicationInstanceManager applicationInstanceManager, NewMusicFridayManager newMusicFridayManager, NewMusicFridayFactory nmfFactory, SpotifyWebApi spotifyWebApi, SpotifyPlaylistManager spotifyPlaylistManager, SonyMusicManager sonyMusicManager, SpotifyTrackManager spotifyTrackManager, ILogger logger, IApolloWebApi apolloWebApi) : base(applicationInstanceManager, logger) { _nmfManager = newMusicFridayManager; _nmfFactory = nmfFactory; _spotifyWebApi = spotifyWebApi; _spotifyPlaylistManager = spotifyPlaylistManager; _sonyMusicManager = sonyMusicManager; _spotifyTrackManager = spotifyTrackManager; _apolloWebApi = apolloWebApi; Get["GetSpotifyTracksForFriday", "/newMusicFriday/spotify/", runAsync: true] = async (parameters, cx) => { PaginatedContent result = await LogActionWrapper.Execute( async () => await GetSpotifyTracksForFriday(Request), Logger, "/newMusicFriday/spotify/ -> GetSpotifyTracksForFriday", ExtractRequestData(Request)); return Response.AsJson(result); }; Post["AddSpotifyNewMusicFridayPlaylist", "/newMusicFriday/spotify/addPlaylist", runAsync: true] = async (parameters, cx) => { var nmfPlaylist = this.Bind(); if (string.IsNullOrWhiteSpace(nmfPlaylist?.PlaylistId) || string.IsNullOrWhiteSpace(nmfPlaylist?.CountryCode)) return HttpStatusCode.BadRequest; var fetchedPlaylist = await _spotifyWebApi.GetPlaylistByIdAsync(nmfPlaylist.PlaylistId); if (fetchedPlaylist?.Tracks == null) return HttpStatusCode.NotFound; if (_spotifyPlaylistManager.GetPlaylistById(nmfPlaylist.PlaylistId) == null) { //build new spotify playlist and add to regular playlists tracking await _spotifyPlaylistManager.AddSpotifyPlaylistsForTrackingAsync(new List() { new SpotifyPlaylistTrackingReference() { PlaylistId = fetchedPlaylist.id, Name = fetchedPlaylist.name, User = fetchedPlaylist.owner.id, SaveTracklist = true } }); } return Response.AsJson(_nmfManager.AddPlaylist(new SpotifyNewMusicFridayPlaylist() { PlaylistId = nmfPlaylist.PlaylistId, Market = nmfPlaylist.CountryCode })); }; Get["GetAllAvailableSpotifyNewMusicFridays", "/newMusicFriday/spotify/availableDates", runAsync: true] = async (parameters, cx) => { return Response.AsJson((await _nmfManager.GetAvailableFridays()).Select(x => x.ToNeutralShortDateString())); }; Get["GetSpotifyPlaylists", "/newMusicFriday/spotify/playlists", runAsync: true] = async (parameters, cx) => { return Response.AsJson((await _nmfFactory.GetPlaylistsData()) .Select(x => new NewMusicFridayPlaylistViewModel() { PlaylistId = x.PlaylistId, Name = x.Name, CountryCode = x.Market.ToLowerInvariant(), Followers = x.Followers, FridayLastUpdatedDate = x.FridayLastUpdatedDate.ToNeutralShortDateString(), TrackLastAdded = x.TrackLastAdded })); }; } private DateTime DetermineDateToUse(Request request) { if (DateTime.TryParse((string)request.Query.date, out var parsedDate)) return parsedDate; return _nmfManager.GetPrecedingOrCurrentFriday(DateTime.UtcNow); } private async Task> GetSpotifyTracksForFriday(Request request) { var date = DetermineDateToUse(request); var market = (string)request.Query.market; //if market is not provided the parameter is null and we fallback to any market var limit = (int?)request.Query.limit ?? 100; var offset = (int?)request.Query.offset ?? 0; PaginatedContent viewModel = await GetTrackListResponseAsync(date, limit, offset, market); return viewModel; } private async Task> GetTrackListResponseAsync(DateTime date, int limit, int offset, string market) { var playlistReferences = _nmfManager.GetPlaylistReferenceCacheItems(); var playlistCollections = await _nmfManager.GetTracklists(playlistReferences.Keys, date); var spotifyPlaylists = _spotifyPlaylistManager.GetPlaylistsByIds(playlistReferences.Keys).ToDictionary(k => k.PlaylistId, v => v); var trackIds = playlistCollections .SelectMany(p => p.Value) .GroupBy(p => p.Isrc).Select(p => { return p.FirstOrDefault(x => !string.IsNullOrEmpty(x.TrackId)).TrackId; //to make sure all data is from the same track we just pick one even though they are grouped by ISRC }).ToList(); Dictionary trackIdIsASonyMap = (await this._apolloWebApi.IsSonyTrack(trackIds, market)) .ToDictionary(t => t.TrackId, t => t.IsSony); var trackViewModels = playlistCollections .SelectMany(p => p.Value) .GroupBy(p => p.Isrc).Select(p => { var track = p.FirstOrDefault(x => !string.IsNullOrEmpty(x.TrackId)); //to make sure all data is from the same track we just pick one even though they are grouped by ISRC return new NewMusicFridayTrackViewModel() { Isrc = p.Key, TrackName = track?.TrackName, TrackId = track?.TrackId, Artists = track?.Artists, Playlists = p.Select(pi => new NewMusicFridayTrackPlaylistReference() { PlaylistId = pi.PlaylistId, Position = pi.PlaylistIndex + 1, CountryCode = playlistReferences[pi.PlaylistId].ToLowerInvariant(), AddedDate = pi.Added, PlaylistImageUrl = spotifyPlaylists[pi.PlaylistId]?.Image }).OrderBy(x => x.Position).ToList(), AlbumImageUrl = track?.AlbumImageUrl, TopTenFeatureCount = p.Count(pi => pi.PlaylistIndex < 10), IsSony = track == null ? false : trackIdIsASonyMap.ContainsKey(track.TrackId) ? trackIdIsASonyMap[track.TrackId] : false }; }).ToArray(); return trackViewModels.OrderByDescending(x => x.Playlists.Count) .ThenByDescending(x => x.TopTenFeatureCount) .ToList() .Paginate(limit, offset); } } }