Example #1
0
        public async Task <IEnumerable <LastFmAlbum> > GetTopAlbums(LastFmDataPeriod period, int count)
        {
            if (period == LastFmDataPeriod.Day)
            {
                var tracks = await GetRecentTracks(StatsPeriodTimeMapping[period]);

                return(tracks
                       .SkipWhile(x => x.NowPlaying)
                       .GroupBy(x => x.Album.Id)
                       .Select(x => x.First().Album.WithPlaycount(x.Count()))
                       .OrderByDescending(x => x.Playcount));
            }
            else
            {
                var request = WebRequest.CreateHttp($"{ApiBase}/?method=user.gettopalbums&user={User}&api_key={Key}&period={StatsPeriodMapping[period]}&limit={count}&format=json");
                request.Timeout = (int)RequestTimeout.TotalMilliseconds;
                using (var response = (HttpWebResponse)await request.GetResponseAsync())
                    using (var reader = new StreamReader(response.GetResponseStream()))
                    {
                        var text = await reader.ReadToEndAsync();

                        var root    = JObject.Parse(text);
                        var results = root?["topalbums"]?["album"] as JArray ?? Enumerable.Empty <JToken>();
                        return(results.Select(x => new LastFmAlbum((string)x["name"], new LastFmArtist((string)x["artist"]["name"]), (int)x["playcount"])));
                    }
            }
        }
Example #2
0
        public async Task <IEnumerable <LastFmScore <LastFmTrack> > > GetTrackScores(LastFmDataPeriod period, int count, Task <int> totalPlaycount)
        {
            var items = await GetTopTracks(period, count);

            var playcount = await totalPlaycount;

            return(items.Select(x => new LastFmScore <LastFmTrack>(x, (double)x.Playcount / playcount)));
        }
Example #3
0
        public async Task <IEnumerable <LastFmTrack> > GetTopTracks(LastFmDataPeriod period, int count = int.MaxValue, CancellationToken ct = default)
        {
            if (period == LastFmDataPeriod.Day)
            {
                var tracks = await GetRecentTracks(StatsPeriodTimeMapping[period]);

                return(tracks
                       .SkipWhile(x => x.NowPlaying)
                       .GroupBy(x => x.Id)
                       .Select(x => x.First().ToTrack(x.Count()))
                       .OrderByDescending(x => x.Playcount));
            }
            else
            {
                var retrieved = 0;
                var page      = 1;
                var results   = Enumerable.Empty <LastFmTrack>();
                var pageSize  = Math.Min(count, MaxTopPageSize);
                while (retrieved < count)
                {
                    ct.ThrowIfCancellationRequested();
                    var request = WebRequest.CreateHttp($"{ApiBase}/?method=user.gettoptracks&user={User}&api_key={Key}&period={StatsPeriodMapping[period]}&limit={pageSize}&page={page}&format=json");
                    request.Timeout = (int)RequestTimeout.TotalMilliseconds;
                    using (var response = (HttpWebResponse)await request.GetResponseAsync())
                        using (var reader = new StreamReader(response.GetResponseStream()))
                        {
                            ct.ThrowIfCancellationRequested();
                            var text = await reader.ReadToEndAsync();

                            ct.ThrowIfCancellationRequested();

                            var root        = JObject.Parse(text);
                            var pageResults = (root?["toptracks"]?["track"] as JArray ?? Enumerable.Empty <JToken>()).ToList();
                            results = results.Concat(pageResults.Select(x => new LastFmTrack((string)x["name"], new LastFmAlbum(null, new LastFmArtist((string)x["artist"]["name"]), null), (int)x["playcount"])));

                            retrieved += pageResults.Count;
                            var more = page < ((int?)root?["toptracks"]?["@attr"]?["totalPages"] ?? 1);
                            if (!more || !pageResults.Any())
                            {
                                break;
                            }
                        }

                    page++;
                }

                return(results);
            }
        }
Example #4
0
        private string FormatStatsDataPeriod(LastFmDataPeriod period)
        {
            switch (period)
            {
            case LastFmDataPeriod.Day: return("data from the last 24 hours");

            case LastFmDataPeriod.Week: return("data from the last week");

            case LastFmDataPeriod.Month: return("data from the last month");

            case LastFmDataPeriod.QuarterYear: return("data from the last 3 months");

            case LastFmDataPeriod.HalfYear: return("data from the last 6 months");

            case LastFmDataPeriod.Year: return("data from the last year");

            case LastFmDataPeriod.Overall: return("all data");

            default: throw new ArgumentException($"Unknown value {period}");
            }
        }
Example #5
0
 public Task <IEnumerable <LastFmRecentTrack> > GetRecentTracks(LastFmDataPeriod period, int count = int.MaxValue)
 => period == LastFmDataPeriod.Overall ? GetRecentTracks(count: count) : GetRecentTracks(StatsPeriodTimeMapping[period], count);
Example #6
0
        public async Task <LastFmArtistDetail> GetArtistDetail(string artist, LastFmDataPeriod period)
        {
            try
            {
                var infoTask = GetArtistInfo(artist);
                var request  = WebRequest.CreateHttp($"https://www.last.fm/user/{User}/library/music/{Uri.EscapeDataString(artist)}?date_preset={StatsPeriodWebMapping[period]}");
                request.Timeout = (int)RequestTimeout.TotalMilliseconds;
                using (var response = (HttpWebResponse)await request.GetResponseAsync())
                    using (var reader = new StreamReader(response.GetResponseStream()))
                    {
                        var content = await reader.ReadToEndAsync();

                        var doc = new HtmlDocument();
                        doc.LoadHtml(content);

                        // Get artist info
                        var info = await infoTask;
                        if (info == null)
                        {
                            return(null);
                        }

                        // Get avatar (we can't get it via the API because it never actually has the artist's image...)
                        var image = doc.DocumentNode.Descendants("span")
                                    .FirstOrDefault(x => x.HasClass("library-header-image"))?
                                    .Descendants("img")
                                    .FirstOrDefault()?
                                    .GetAttributeValue("src", null)?
                                    .Replace("avatar70s", "avatar170s");

                        // Get playcount and count of listened albums and tracks (in that order)
                        var metadata = doc.DocumentNode
                                       .Descendants("p")
                                       .Where(x => x.HasClass("metadata-display") && x.ParentNode.HasClass("metadata-item"))
                                       .Select(x => int.Parse(x.InnerText, System.Globalization.NumberStyles.Any, new System.Globalization.CultureInfo("en-US")))
                                       .ToList();

                        var playcount      = metadata.ElementAtOrDefault(0);
                        var albumsListened = metadata.ElementAtOrDefault(1);
                        var tracksListened = metadata.ElementAtOrDefault(2);

                        // Get top albums and tracks
                        IEnumerable <(string name, string url, int playcount)> GetTopListItems(HtmlNode topList)
                        {
                            foreach (var item in topList.Descendants("tr").Where(x => x.HasClass("chartlist-row") || x.HasClass("chartlist-row\n")))
                            {
                                var itemNameLink = item.Descendants("td").First(x => x.HasClass("chartlist-name")).Descendants("a").First();
                                var itemUrl      = "https://www.last.fm" + itemNameLink.GetAttributeValue("href", null);

                                var scrobbleText  = item.Descendants("span").First(x => x.HasClass("chartlist-count-bar-value")).InnerText;
                                var scrobbleCount = int.Parse(Regex.Match(scrobbleText, @"[\d,.\s]+").Value, System.Globalization.NumberStyles.Any, new System.Globalization.CultureInfo("en-US"));
                                yield return(WebUtility.HtmlDecode(itemNameLink.InnerText), itemUrl, scrobbleCount);
                            }
                        }

                        var topLists  = doc.DocumentNode.Descendants("table").Where(x => x.HasClass("chartlist") || x.HasClass("chartlist\n")).ToList();
                        var topAlbums = Enumerable.Empty <LastFmAlbum>();
                        if (topLists.Any())
                        {
                            topAlbums = GetTopListItems(topLists.First()).Select(x => new LastFmAlbum(x.name, info, x.playcount));
                        }

                        var topTracks = Enumerable.Empty <LastFmTrack>();
                        if (topLists.Skip(1).Any())
                        {
                            topTracks = GetTopListItems(topLists.Skip(1).First()).Select(x => new LastFmTrack(x.name, new LastFmAlbum(null, info), x.playcount));
                        }

                        var imageUri = string.IsNullOrEmpty(image) ? null : new Uri(image);
                        return(new LastFmArtistDetail(info, imageUri, topAlbums, topTracks, albumsListened, tracksListened, playcount));
                    }
            }
            catch (WebException e) when((e.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotFound)
            {
                return(null);
            }
        }
Example #7
0
 public Task <int> GetTotalPlaycount(LastFmDataPeriod period)
 => period == LastFmDataPeriod.Overall ? GetTotalPlaycount() : GetTotalPlaycount(StatsPeriodTimeMapping[period]);