using Amazon.S3; using Amazon.S3.Transfer; using Sony.Filtr.Core.SpotifyCharts.Api; using Sony.Filtr.Core.SpotifyCharts.Data; using System; using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; using Sony.Filtr.Utility.Extensions; using Sony.Filtr.Core.SpotifyCharts.Extensions; using Sony.Filtr.Utility; namespace Sony.Filtr.Core.SpotifyCharts { public class SpotifyChartsS3Api { private readonly AmazonS3Client _s3Client; public SpotifyChartsS3Api(AmazonS3Client s3Client) { _s3Client = s3Client; } private static Lazy getCSV_Bucket = new Lazy(() => Maybe.GetAppSettingsStringOrDefault("SpotifyChartsS3Api_CSV_Bucket", "prod-apollo-spotify-charts")); private static string CSV_Bucket => getCSV_Bucket.Value; public async Task GetChartDataFromS3Async(ChartData chart) { if (chart.Date.HasValue == false || chart.Equals(ChartData.Empty)) { return null; } var csvStream = await DownloadS3FileAsStreamAsync(chart.ToString()); if (csvStream == null) { return null; } var chartEntries = new StreamLinesChartReader(csvStream, chart).ToChartItems(); if (chartEntries.IsNullOrEmpty()) { return null; } var saveInformation = new ChartDataSaveInformation() { ChartsListType = chart.ListType, Market = chart.Market, ChartsTimeWindow = chart.TimeWindow, Date = GetChartDataDateTime(chart), ChartItems = chartEntries.ToList() }; return saveInformation; } private static DateTime GetChartDataDateTime(ChartData chart) { Func isWeeklyRegionalThursday = c => c.TimeWindow == SpotifyChartsTimeWindow.Weekly && c.ListType == SpotifyChartsListType.Regional && chart.Date.Value.DayOfWeek == DayOfWeek.Thursday; /* Weekly charts on spotifycharts.com are generated on Thursdays But portal and probably some other services using our DB require weekly charts to be from Friday to Friday */ return isWeeklyRegionalThursday(chart) ? chart.Date.Value.AddDays(1) : chart.Date.Value; } private async Task DownloadS3FileAsStreamAsync(string key) { //return File.OpenRead(@"C:\projects\filter-api\filtr-api\Sony.Filtr.ScheduledTask\bin\Debug\logs\csvs\spotifycharts_2021-05-03_at.csv"); var transferUtility = new TransferUtility(_s3Client); try { return await transferUtility.OpenStreamAsync(new TransferUtilityOpenStreamRequest() { BucketName = CSV_Bucket, Key = key, }); } catch (Exception ex) { return null; } } } public struct ChartData { public static ChartData Empty = new ChartData(); public readonly string Market; public readonly DateTime? Date; public readonly SpotifyChartsListType ListType; public readonly SpotifyChartsTimeWindow TimeWindow; private string OriginalFilePath; public string FilePath { get { return $"spotifycharts/{this.TimeWindow.ToString().ToLower()}/{this.ListType.ToString().ToLower()}/{(this.Date.HasValue ? this.Date.Value.ToString("yyyy-MM-dd") : "empty")}/{this.Market}.csv"; } } public ChartData(string market, DateTime? date, SpotifyChartsListType listType, SpotifyChartsTimeWindow timeWindow) { this.Market = market; this.Date = date; this.ListType = listType; this.TimeWindow = timeWindow; this.OriginalFilePath = String.Empty; } public static ChartData Parse(string filePath) { try { //{daily or weekly}/{regional or viral}/{YYYY-mm-dd}/{market}.csv var segments = filePath.Split('/'); if (segments.Length != 5) { return Empty; } var chart = new ChartData( Path.GetFileNameWithoutExtension(segments[4]), DateTime.ParseExact(segments[3], "yyyy-MM-dd", CultureInfo.CurrentCulture.DateTimeFormat), segments[2].ParseAsEnum(), segments[1].ParseAsEnum()); chart.OriginalFilePath = filePath; return chart; } catch (Exception ex) { return Empty; } } public override bool Equals(object obj) { if (obj == null) { return false; } if (this.GetType() != obj.GetType()) { return false; } return this.Equals((ChartData)obj); } public bool Equals(ChartData other) { return this.Market == other.Market && this.Date == other.Date && this.ListType == other.ListType && this.TimeWindow == other.TimeWindow; } public override int GetHashCode() { return 672617347 ^ this.Market.GetHashCode() ^ this.Date.GetHashCode() ^ this.TimeWindow.GetHashCode() ^ this.ListType.GetHashCode(); } public override string ToString() { return this.FilePath; } } }