/// <summary> /// /// </summary> /// <param name="page"></param> /// <param name="cancellationToken"></param> /// <exception cref="InvalidFeedSettingsException">Thrown when the feed's settings aren't valid.</exception> /// <returns></returns> public async Task <PageReadResult> GetSongsAsync(Uri uri, CancellationToken cancellationToken) { string pageText = ""; Dictionary <string, ScrapedSong> songs = new Dictionary <string, ScrapedSong>(); Logger.Debug($"Getting songs from '{uri}'"); IWebResponseMessage?response = null; try { response = await WebUtils.WebClient.GetAsync(uri, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); pageText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } catch (OperationCanceledException ex) { return(PageReadResult.CancelledResult(uri, ex)); } catch (WebClientException ex) { string errorText = string.Empty; int statusCode = ex?.Response?.StatusCode ?? 0; if (statusCode != 0) { switch (statusCode) { case 404: errorText = $"{uri.ToString()} was not found."; break; case 408: errorText = $"Timeout getting first page in ScoreSaberReader: {uri}: {ex.Message}"; break; default: errorText = $"Site Error getting first page in ScoreSaberReader: {uri}: {ex.Message}"; break; } } Logger?.Debug(errorText); // No need for a stacktrace if it's one of these errors. if (!(statusCode == 404 || statusCode == 408 || statusCode == 500)) { Logger?.Debug($"{ex.Message}\n{ex.StackTrace}"); } return(PageReadResult.FromWebClientException(ex, uri)); } catch (Exception ex) { string message = $"Uncaught error getting the first page in ScoreSaberReader.GetSongsFromScoreSaberAsync(): {ex.Message}"; return(new PageReadResult(uri, new List <ScrapedSong>(), null, null, 0, new FeedReaderException(message, ex, FeedReaderFailureCode.SourceFailed), PageErrorType.Unknown)); } finally { response?.Dispose(); response = null; } bool isLastPage; ScrapedSong?firstSong = null; ScrapedSong?lastSong = null; int songsOnPage = 0; try { List <ScrapedSong>?diffs = GetSongsFromPageText(pageText, uri, Settings.StoreRawData || StoreRawData); firstSong = diffs?.FirstOrDefault(); lastSong = diffs?.LastOrDefault(); songsOnPage = diffs?.Count ?? 0; isLastPage = (diffs?.Count ?? 0) < SongsPerPage; foreach (ScrapedSong?diff in diffs) { if (!songs.ContainsKey(diff.Hash) && (Settings.Filter == null || Settings.Filter(diff))) { songs.Add(diff.Hash, diff); } if (Settings.StopWhenAny != null && Settings.StopWhenAny(diff)) { isLastPage = true; } } } catch (JsonReaderException ex) { string message = "Unable to parse JSON from text"; Logger?.Debug($"{message}: {ex.Message}\n{ex.StackTrace}"); return(new PageReadResult(uri, null, firstSong, lastSong, songsOnPage, new FeedReaderException(message, ex, FeedReaderFailureCode.PageFailed), PageErrorType.ParsingError)); } catch (Exception ex) { string message = $"Unhandled exception from GetSongsFromPageText() while parsing {uri}"; Logger?.Debug($"{message}: {ex.Message}\n{ex.StackTrace}"); return(new PageReadResult(uri, null, firstSong, lastSong, songsOnPage, new FeedReaderException(message, ex, FeedReaderFailureCode.PageFailed), PageErrorType.ParsingError)); } return(new PageReadResult(uri, songs.Values.ToList(), firstSong, lastSong, songsOnPage, isLastPage)); }
/// <summary> /// /// </summary> /// <param name="page"></param> /// <param name="cancellationToken"></param> /// <exception cref="InvalidFeedSettingsException">Thrown when the feed's settings aren't valid.</exception> /// <returns></returns> public async Task <PageReadResult> GetSongsAsync(Uri uri, CancellationToken cancellationToken) { string pageText; JObject result; List <ScrapedSong> newSongs; Logger.Debug($"Getting songs from '{uri}'"); //int? lastPage; bool isLastPage = false; IWebResponseMessage?response = null; ScrapedSong? firstSong = null; ScrapedSong? lastSong = null; int songsOnPage = 0; try { response = await WebUtils.GetBeatSaverAsync(uri, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); #pragma warning disable CS8602 // Dereference of a possibly null reference. pageText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); #pragma warning restore CS8602 // Dereference of a possibly null reference. result = JObject.Parse(pageText); if (result?["docs"] == null) { Logger?.Warning($"Error checking Beat Saver's {Name} feed."); return(new PageReadResult(uri, null, null, null, 0, new FeedReaderException($"Error getting page in BeatSaverFeed.GetSongsFromPageAsync()", null, FeedReaderFailureCode.PageFailed), PageErrorType.ParsingError)); } //if (configuredLastPage > 0) // isLastPage = Math.Min(configuredLastPage, lastPage.Value) <= page; //else // isLastPage = page >= lastPage.Value; newSongs = new List <ScrapedSong>(); var scrapedSongs = BeatSaverReader.ParseSongsFromJson(result, uri, Settings.StoreRawData || StoreRawData); firstSong = scrapedSongs.FirstOrDefault(); lastSong = scrapedSongs.LastOrDefault(); songsOnPage = scrapedSongs.Count; foreach (var song in scrapedSongs) { if (Settings.Filter == null || Settings.Filter(song)) { newSongs.Add(song); } if (Settings.StopWhenAny != null && Settings.StopWhenAny(song)) { isLastPage = true; break; } } if (scrapedSongs.Count == 0) { isLastPage = true; } } catch (WebClientException ex) { string errorText = string.Empty; if (ex.Response != null) { switch (ex.Response.StatusCode) { case 408: errorText = "Timeout"; break; default: errorText = "Site Error"; break; } } string message = $"{errorText} getting a response from {uri}: {ex.Message}"; Logger?.Debug(message); Logger?.Debug($"{ex.Message}\n{ex.StackTrace}"); return(PageReadResult.FromWebClientException(ex, uri)); } catch (JsonReaderException ex) { string message = $"Unable to parse JSON from text on page {uri.ToString()}"; Logger?.Debug(message); Logger?.Debug($"{ex.Message}\n{ex.StackTrace}"); return(new PageReadResult(uri, null, firstSong, lastSong, songsOnPage, new FeedReaderException(message, ex, FeedReaderFailureCode.SourceFailed), PageErrorType.ParsingError)); } catch (OperationCanceledException ex) { return(PageReadResult.CancelledResult(uri, ex)); } catch (Exception ex) { string message = $"Uncaught error getting page {uri} in BeatSaverFeed.GetSongsFromPageAsync(): {ex.Message}"; return(new PageReadResult(uri, null, firstSong, lastSong, songsOnPage, new FeedReaderException(message, ex, FeedReaderFailureCode.SourceFailed), PageErrorType.ParsingError)); } finally { response?.Dispose(); response = null; } //if (lastPage.HasValue && !isLastPage) // return new BeatSaverPageResult(pageUri, newSongs, page, lastPage.Value); //else return(new PageReadResult(uri, newSongs, firstSong, lastSong, songsOnPage, isLastPage)); }