using AngleSharp.Dom; using Sony.Filtr.Core.SpotifyCharts.Data; using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; namespace Sony.Filtr.Core.SpotifyCharts.Extensions { public static class SpotifyChartHTMLExtensions { public static IEnumerable ToChartItems(this IDocument document) { if (document == null) { return Enumerable.Empty(); } var cssSelector = "table.chart-table tr"; var trs = document.QuerySelectorAll(cssSelector); var items = new List(); if (trs != null) { foreach (var tr in trs) { var item = tr.ToChartItem(); if (item != null) { items.Add(item); } } } return items; } public static ChartItemCsv ToChartItem(this IElement tr) { var item = new ChartItemCsv(); tr .AddLinkAndId(item) .AddStreams(item) .AddTrackPosition(item) .AddTrackNameAndArtist(item); return item.ReturnItemIfValidOrNULL(); } private static ChartItemCsv ReturnItemIfValidOrNULL(this ChartItemCsv item) { if (!String.IsNullOrWhiteSpace(item.ArtistName) && !String.IsNullOrWhiteSpace(item.TrackName) && !String.IsNullOrWhiteSpace(item.TrackUrl) && !String.IsNullOrWhiteSpace(item.TrackId)) { return item; } return null; } private static IElement AddLinkAndId(this IElement tr, ChartItemCsv item) { var anchor = tr.QuerySelector("td.chart-table-image a"); if (anchor != null) { var trackLink = anchor.GetAttribute("href"); if (!String.IsNullOrWhiteSpace(trackLink)) { item.TrackUrl = trackLink; var uri = new Uri(trackLink); if (uri.Segments != null && uri.Segments.Length == 3 && uri.Segments[1].ToLower() == "track/") { item.TrackId = uri.Segments[2]; } } } return tr; } private static Regex NonDigitRegex = new Regex(@"[^\d]"); private static IElement AddStreams(this IElement tr, ChartItemCsv item) { var streamsTD = tr.QuerySelector("td.chart-table-streams"); if (streamsTD != null) { if (Int32.TryParse(NonDigitRegex.Replace(streamsTD.InnerHtml, ""), out int streams)) { item.NumberOfStreams = streams; } } return tr; } private static IElement AddTrackPosition(this IElement tr, ChartItemCsv item) { var positionTD = tr.QuerySelector("td.chart-table-position"); if (positionTD != null) { if (Int32.TryParse(positionTD.InnerHtml, out int position)) { item.Position = position; } } return tr; } private static Regex ArtistNameRegex = new Regex("^by (.+)$", RegexOptions.IgnoreCase); private static IElement AddTrackNameAndArtist(this IElement tr, ChartItemCsv item) { var trackTD = tr.QuerySelector("td.chart-table-track"); if (trackTD != null) { var nameStrong = trackTD.QuerySelector("strong"); if (nameStrong != null) { item.TrackName = System.Net.WebUtility.HtmlDecode(nameStrong.InnerHtml); } var artistSpan = trackTD.QuerySelector("span"); if (artistSpan != null) { var match = ArtistNameRegex.Match(artistSpan.InnerHtml); if (match.Success) { item.ArtistName = System.Net.WebUtility.HtmlDecode(match.Groups[1].Value.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)[0]); } } } return tr; } } }