diff --git a/LyricsScraperNET.Client/Program.cs b/LyricsScraperNET.Client/Program.cs index 93b9575..e520cbd 100644 --- a/LyricsScraperNET.Client/Program.cs +++ b/LyricsScraperNET.Client/Program.cs @@ -12,6 +12,7 @@ using LyricsScraperNET.Models.Responses; using System.Threading.Tasks; using System; +using Microsoft.Extensions.Logging; class Program { @@ -21,18 +22,33 @@ static async Task Main() string artistToSearch = "Parkway Drive"; string songToSearch = "Idols And Anchors"; + //// The case when a song contains only an instrumental, without vocals. + //string artistToSearch = "Rush"; + //string songToSearch = "YYZ"; + //// How to configure for ASP.NET applications: var result = ExampleWithHostConfiguration(artistToSearch, songToSearch); //// How to configure for a certain external provider: //var result = ExampleWithCertainProvider(artistToSearch, songToSearch); - //// Checking if something was found. - //// If not, search errors can be found in the logs. + //// Checking that something was found. The response can be empty in two cases: + //// 1) A search error occurred. Detailed information can be found in the logs or in response fields like 'ResponseStatusCode' and 'ResponseMessage'. + //// 2) The requested song contains only the instrumental, no lyrics. In this case the flag 'Instrumental' will be true. if (result.IsEmpty()) { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine($"Can't find lyrics for: {artistToSearch} - {songToSearch}"); + if (result.Instrumental) + { + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine($"This song [{artistToSearch} - {songToSearch}] is instrumental.\r\nIt does not contain any lyrics"); + } + else + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"Can't find lyrics for: [{artistToSearch} - {songToSearch}]. " + + $"Status code: [{result.ResponseStatusCode}]. " + + $"Response message: [{result.ResponseMessage}]."); + } Console.ResetColor(); Console.ReadLine(); @@ -41,13 +57,13 @@ static async Task Main() //// Output result to console Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine($"{artistToSearch} - {songToSearch}\r\n"); + Console.WriteLine($"[{artistToSearch} - {songToSearch}]\r\n"); Console.ResetColor(); Console.WriteLine(result.LyricText); Console.ForegroundColor = ConsoleColor.Magenta; - Console.WriteLine($"\r\nThis text was found by {result.ExternalProviderType}\r\n"); + Console.WriteLine($"\r\nThis lyric was found by [{result.ExternalProviderType}]\r\n"); Console.ResetColor(); Console.ReadLine(); @@ -105,6 +121,16 @@ ILyricsScraperClient lyricsScraperClient .WithSongLyrics() .WithLyricFind(); + // To enable library logging, the LoggerFactory must be configured and passed to the client. + var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddFilter("Microsoft", LogLevel.Warning) + .AddFilter("System", LogLevel.Warning) + .AddFilter("LyricsScraperNET", LogLevel.Trace) + .AddConsole(); + }); + lyricsScraperClient.WithLogger(loggerFactory); + //// Another way to configure: //// 1. First create instance of LyricScraperClient. // ILyricsScraperClient lyricsScraperClient = new LyricsScraperClient(); diff --git a/LyricsScraperNET.TestShared/TestModel/LyricsTestData.cs b/LyricsScraperNET.TestShared/TestModel/LyricsTestData.cs index 0360579..a44b2c4 100644 --- a/LyricsScraperNET.TestShared/TestModel/LyricsTestData.cs +++ b/LyricsScraperNET.TestShared/TestModel/LyricsTestData.cs @@ -10,8 +10,11 @@ public class LyricsTestData public string SongName { get; set; } public string SongUri { get; set; } - public string LyricPageData => File.ReadAllText(LyricPagePath); + public string LyricPageData => ReadFileData(LyricPagePath); - public string LyricResultData => File.ReadAllText(LyricResultPath); + public string LyricResultData => ReadFileData(LyricResultPath); + + private string ReadFileData(string path) => + !string.IsNullOrEmpty(path) ? File.ReadAllText(path) : string.Empty; } } diff --git a/LyricsScraperNET/Extensions/SearchResultExtensions.cs b/LyricsScraperNET/Extensions/SearchResultExtensions.cs index b82bb9e..88887b5 100644 --- a/LyricsScraperNET/Extensions/SearchResultExtensions.cs +++ b/LyricsScraperNET/Extensions/SearchResultExtensions.cs @@ -29,5 +29,12 @@ internal static SearchResult AppendResponseMessage(this SearchResult searchResul : responseMessage; return searchResult; } + + internal static SearchResult AddInstrumental(this SearchResult searchResult, bool instrumental) + { + searchResult.ResponseStatusCode = ResponseStatusCode.Success; + searchResult.Instrumental = instrumental; + return searchResult; + } } } diff --git a/LyricsScraperNET/ILyricsScraperClient.cs b/LyricsScraperNET/ILyricsScraperClient.cs index e493176..a12e6b6 100644 --- a/LyricsScraperNET/ILyricsScraperClient.cs +++ b/LyricsScraperNET/ILyricsScraperClient.cs @@ -2,6 +2,7 @@ using LyricsScraperNET.Models.Responses; using LyricsScraperNET.Providers.Abstract; using LyricsScraperNET.Providers.Models; +using Microsoft.Extensions.Logging; using System.Threading.Tasks; namespace LyricsScraperNET @@ -49,5 +50,11 @@ public interface ILyricsScraperClient /// Calling the lyrics search method will return an empty result. /// void Disable(); + + /// + /// Creates a new ILogger instance from . + /// Can be useful for error analysis if the lyric text is not found. + /// + void WithLogger(ILoggerFactory loggerFactory); } } diff --git a/LyricsScraperNET/LyricsScraperClient.cs b/LyricsScraperNET/LyricsScraperClient.cs index dc5e33f..d43c01a 100644 --- a/LyricsScraperNET/LyricsScraperClient.cs +++ b/LyricsScraperNET/LyricsScraperClient.cs @@ -16,8 +16,8 @@ namespace LyricsScraperNET { public sealed class LyricsScraperClient : ILyricsScraperClient { - - private readonly ILogger _logger; + private ILoggerFactory _loggerFactory; + private ILogger _logger; private List _externalProviders; private readonly ILyricScraperClientConfig _lyricScraperClientConfig; @@ -70,15 +70,15 @@ public SearchResult SearchLyric(SearchRequest searchRequest) foreach (var externalProvider in GetAvailableProvidersForSearchRequest(searchRequest)) { var providerSearchResult = externalProvider.SearchLyric(searchRequest); - if (!providerSearchResult.IsEmpty()) + if (!providerSearchResult.IsEmpty() || providerSearchResult.Instrumental) { return providerSearchResult; } - _logger?.LogWarning($"Can't find lyric by provider: {externalProvider}."); + _logger?.LogWarning($"Can't find lyric by provider: [{externalProvider.Options?.ExternalProviderType}]."); } searchResult.AddNoDataFoundMessage(Constants.ResponseMessages.NotFoundLyric); - _logger?.LogError($"Can't find lyrics for searchRequest: {searchRequest}."); + _logger?.LogError($"Can't find lyrics for searchRequest: [{searchRequest}]."); return searchResult; } @@ -102,15 +102,15 @@ public async Task SearchLyricAsync(SearchRequest searchRequest) foreach (var externalProvider in GetAvailableProvidersForSearchRequest(searchRequest)) { var providerSearchResult = await externalProvider.SearchLyricAsync(searchRequest); - if (!providerSearchResult.IsEmpty()) + if (!providerSearchResult.IsEmpty() || providerSearchResult.Instrumental) { return providerSearchResult; } - _logger?.LogWarning($"Can't find lyric by provider: {externalProvider}."); + _logger?.LogWarning($"Can't find lyric by provider: [{externalProvider.Options?.ExternalProviderType}]."); } searchResult.AddNoDataFoundMessage(Constants.ResponseMessages.NotFoundLyric); - _logger?.LogError($"Can't find lyrics for searchRequest: {searchRequest}."); + _logger?.LogError($"Can't find lyrics for searchRequest: [{searchRequest}]."); return searchResult; } @@ -200,7 +200,11 @@ public void AddProvider(IExternalProvider provider) if (IsEmptyProvidersList()) _externalProviders = new List(); if (!_externalProviders.Contains(provider)) + { + if (_loggerFactory != null) + provider.WithLogger(_loggerFactory); _externalProviders.Add(provider); + } else _logger?.LogWarning($"External provider {provider} already added"); } @@ -219,9 +223,7 @@ public void Enable() return; foreach (var provider in _externalProviders) - { provider.Enable(); - } } public void Disable() @@ -230,9 +232,19 @@ public void Disable() return; foreach (var provider in _externalProviders) - { provider.Disable(); - } + } + + public void WithLogger(ILoggerFactory loggerFactory) + { + _loggerFactory = loggerFactory; + _logger = loggerFactory.CreateLogger(); + + if (IsEmptyProvidersList()) + return; + + foreach (var provider in _externalProviders) + provider.WithLogger(loggerFactory); } private bool IsEmptyProvidersList() => _externalProviders == null || !_externalProviders.Any(); diff --git a/LyricsScraperNET/Models/Requests/ArtistAndSongSearchRequest.cs b/LyricsScraperNET/Models/Requests/ArtistAndSongSearchRequest.cs index d0e4b5e..4572372 100644 --- a/LyricsScraperNET/Models/Requests/ArtistAndSongSearchRequest.cs +++ b/LyricsScraperNET/Models/Requests/ArtistAndSongSearchRequest.cs @@ -34,5 +34,10 @@ public ArtistAndSongSearchRequest(string artist, string song, ExternalProviderTy { Provider = provider; } + + public override string ToString() + { + return $"Artist: [{Artist}]. Song: [{Song}]. Provider: [{Provider}]"; + } } } diff --git a/LyricsScraperNET/Models/Requests/UriSearchRequest.cs b/LyricsScraperNET/Models/Requests/UriSearchRequest.cs index 6e8f27a..5620b95 100644 --- a/LyricsScraperNET/Models/Requests/UriSearchRequest.cs +++ b/LyricsScraperNET/Models/Requests/UriSearchRequest.cs @@ -35,5 +35,10 @@ public UriSearchRequest(string uri) : this(new Uri(uri)) public UriSearchRequest(string uri, ExternalProviderType provider) : this(new Uri(uri), provider) { } + + public override string ToString() + { + return $"Uri: [{Uri}]. Provider: [{Provider}]"; + } } } diff --git a/LyricsScraperNET/Models/Responses/SearchResult.cs b/LyricsScraperNET/Models/Responses/SearchResult.cs index b27cf73..7e09bfe 100644 --- a/LyricsScraperNET/Models/Responses/SearchResult.cs +++ b/LyricsScraperNET/Models/Responses/SearchResult.cs @@ -47,6 +47,11 @@ internal SearchResult(string lyricText, ExternalProviderType externalProviderTyp /// public string ResponseMessage { get; internal set; } = string.Empty; + /// + /// The flag indicates that the search results are for music only, without text. + /// + public bool Instrumental { get; internal set; } = false; + /// /// Returns true if the field is empty. /// diff --git a/LyricsScraperNET/Providers/AZLyrics/AZLyricsProvider.cs b/LyricsScraperNET/Providers/AZLyrics/AZLyricsProvider.cs index c2a349b..7e3957e 100644 --- a/LyricsScraperNET/Providers/AZLyrics/AZLyricsProvider.cs +++ b/LyricsScraperNET/Providers/AZLyrics/AZLyricsProvider.cs @@ -11,7 +11,7 @@ namespace LyricsScraperNET.Providers.AZLyrics { public sealed class AZLyricsProvider : ExternalProviderBase { - private readonly ILogger _logger; + private ILogger _logger; private readonly IExternalUriConverter _uriConverter; private const string _lyricStart = ""; @@ -68,7 +68,7 @@ protected override SearchResult SearchLyric(Uri uri) if (WebClient == null || Parser == null) { _logger?.LogWarning($"AZLyrics. Please set up WebClient and Parser first"); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.AZLyrics); } var text = WebClient.Load(uri); return PostProcessLyric(uri, text); @@ -88,7 +88,7 @@ protected override async Task SearchLyricAsync(Uri uri) if (WebClient == null || Parser == null) { _logger?.LogWarning($"AZLyrics. Please set up WebClient and Parser first"); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.AZLyrics); } var text = await WebClient.LoadAsync(uri); return PostProcessLyric(uri, text); @@ -96,20 +96,25 @@ protected override async Task SearchLyricAsync(Uri uri) #endregion + public override void WithLogger(ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + } + private SearchResult PostProcessLyric(Uri uri, string text) { if (string.IsNullOrEmpty(text)) { - _logger?.LogWarning($"AZLyrics. Text is empty for {uri}"); - return new SearchResult(); + _logger?.LogWarning($"AZLyrics. Text is empty for Uri: [{uri}]"); + return new SearchResult(Models.ExternalProviderType.AZLyrics); } var startIndex = text.IndexOf(_lyricStart); var endIndex = text.IndexOf(_lyricEnd); if (startIndex <= 0 || endIndex <= 0) { - _logger?.LogWarning($"AZLyrics. Can't find lyrics for {uri}"); - return new SearchResult(); + _logger?.LogWarning($"AZLyrics. Can't find lyrics for Uri: [{uri}]"); + return new SearchResult(Models.ExternalProviderType.AZLyrics); } string result = Parser.Parse(text.Substring(startIndex, endIndex - startIndex)); diff --git a/LyricsScraperNET/Providers/Abstract/ExternalProviderBase.cs b/LyricsScraperNET/Providers/Abstract/ExternalProviderBase.cs index ec0ef29..acfcdba 100644 --- a/LyricsScraperNET/Providers/Abstract/ExternalProviderBase.cs +++ b/LyricsScraperNET/Providers/Abstract/ExternalProviderBase.cs @@ -1,6 +1,7 @@ using LyricsScraperNET.Models.Requests; using LyricsScraperNET.Models.Responses; using LyricsScraperNET.Network.Abstract; +using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; @@ -95,5 +96,8 @@ public void Disable() if (Options != null) Options.Enabled = false; } + + public virtual void WithLogger(ILoggerFactory loggerFactory) + => throw new NotImplementedException(); } } diff --git a/LyricsScraperNET/Providers/Abstract/IExternalProvider.cs b/LyricsScraperNET/Providers/Abstract/IExternalProvider.cs index d91639f..a581ef7 100644 --- a/LyricsScraperNET/Providers/Abstract/IExternalProvider.cs +++ b/LyricsScraperNET/Providers/Abstract/IExternalProvider.cs @@ -1,6 +1,7 @@ using LyricsScraperNET.Models.Requests; using LyricsScraperNET.Models.Responses; using LyricsScraperNET.Network.Abstract; +using Microsoft.Extensions.Logging; using System.Threading.Tasks; namespace LyricsScraperNET.Providers.Abstract @@ -27,5 +28,7 @@ public interface IExternalProvider void Enable(); void Disable(); + + void WithLogger(ILoggerFactory loggerFactory); } } diff --git a/LyricsScraperNET/Providers/Genius/GeniusProvider.cs b/LyricsScraperNET/Providers/Genius/GeniusProvider.cs index 515404c..681a04d 100644 --- a/LyricsScraperNET/Providers/Genius/GeniusProvider.cs +++ b/LyricsScraperNET/Providers/Genius/GeniusProvider.cs @@ -17,7 +17,7 @@ namespace LyricsScraperNET.Providers.Genius { public sealed class GeniusProvider : ExternalProviderBase { - private readonly ILogger _logger; + private ILogger _logger; private readonly IExternalUriConverter _uriConverter; // Format: "artist song". Example: "Parkway Drive Carrion". @@ -26,6 +26,10 @@ public sealed class GeniusProvider : ExternalProviderBase private const string _referentFragmentNodesXPath = "//a[contains(@class, 'ReferentFragmentVariantdesktop') or contains(@class, 'ReferentFragmentdesktop')]"; private const string _lyricsContainerNodesXPath = "//div[@data-lyrics-container]"; + // In case of instrumental song without a lyric. + private const string _lyricsPlaceholderNodesXPath = "//div[contains(@class, 'LyricsPlaceholder')]"; + private const string _instrumentalLyricText = "This song is an instrumental"; + #region Constructors public GeniusProvider() @@ -71,7 +75,10 @@ protected override SearchResult SearchLyric(Uri uri) { var htmlPageBody = WebClient.Load(uri); - return new SearchResult(GetParsedLyricFromHtmlPageBody(htmlPageBody), Models.ExternalProviderType.Genius); + var lyricResult = GetParsedLyricFromHtmlPageBody(htmlPageBody, out var instrumental); + + return new SearchResult(lyricResult, Models.ExternalProviderType.Genius) + .AddInstrumental(instrumental); } protected override SearchResult SearchLyric(string artist, string song) @@ -94,7 +101,7 @@ protected override SearchResult SearchLyric(string artist, string song) return !string.IsNullOrWhiteSpace(lyricUrl) ? SearchLyric(new Uri(lyricUrl)) - : new SearchResult(); + : new SearchResult(Models.ExternalProviderType.Genius); } #endregion @@ -105,7 +112,10 @@ protected override async Task SearchLyricAsync(Uri uri) { var htmlPageBody = await WebClient.LoadAsync(uri); - return new SearchResult(GetParsedLyricFromHtmlPageBody(htmlPageBody), Models.ExternalProviderType.Genius); + var lyricResult = GetParsedLyricFromHtmlPageBody(htmlPageBody, out var instrumental); + + return new SearchResult(lyricResult, Models.ExternalProviderType.Genius) + .AddInstrumental(instrumental); } protected override async Task SearchLyricAsync(string artist, string song) @@ -128,11 +138,16 @@ protected override async Task SearchLyricAsync(string artist, stri return !string.IsNullOrWhiteSpace(lyricUrl) ? await SearchLyricAsync(new Uri(lyricUrl)) - : new SearchResult(); + : new SearchResult(Models.ExternalProviderType.Genius); } #endregion + public override void WithLogger(ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + } + private string GetLyricUrlWithoutApiKey(string artist, string song) { var htmlPageBody = WebClient.Load(_uriConverter.GetLyricUri(artist, song)); @@ -160,8 +175,10 @@ private string GetLyricUrlWithoutApiKey(string artist, string song) return string.Empty; } - private string GetParsedLyricFromHtmlPageBody(string htmlPageBody) + private string GetParsedLyricFromHtmlPageBody(string htmlPageBody, out bool instrumental) { + instrumental = false; + var htmlDocument = new HtmlDocument(); htmlDocument.LoadHtml(htmlPageBody.Replace("https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js", "")); @@ -175,8 +192,20 @@ private string GetParsedLyricFromHtmlPageBody(string htmlPageBody) spanNode.Remove(); var lyricNodes = htmlDocument.DocumentNode.SelectNodes(_lyricsContainerNodesXPath); + if (lyricNodes == null) + { + // lyricNodes could be null in case of instrumental. + var instrumentalNodes = htmlDocument.DocumentNode.SelectNodes(_lyricsPlaceholderNodesXPath); + if (instrumentalNodes != null + && instrumentalNodes.Any(node => node.InnerHtml.Contains(_instrumentalLyricText))) + { + instrumental = true; + return string.Empty; + } + _logger?.LogWarning($"Genius. Can't parse lyric from the page."); + } - return Parser.Parse(string.Join("", lyricNodes.Select(Node => Node.InnerHtml))); + return Parser.Parse(string.Join("", lyricNodes.Select(node => node.InnerHtml))); } private string GetLyricUrlFromSearchResponse(SearchResponse searchResponse, string artist, string song) diff --git a/LyricsScraperNET/Providers/LyricFind/LyricFindProvider.cs b/LyricsScraperNET/Providers/LyricFind/LyricFindProvider.cs index 549c064..e76b20b 100644 --- a/LyricsScraperNET/Providers/LyricFind/LyricFindProvider.cs +++ b/LyricsScraperNET/Providers/LyricFind/LyricFindProvider.cs @@ -1,4 +1,5 @@ -using LyricsScraperNET.Helpers; +using LyricsScraperNET.Extensions; +using LyricsScraperNET.Helpers; using LyricsScraperNET.Models.Responses; using LyricsScraperNET.Network; using LyricsScraperNET.Providers.Abstract; @@ -11,11 +12,19 @@ namespace LyricsScraperNET.Providers.LyricFind { public sealed class LyricFindProvider : ExternalProviderBase { - private readonly ILogger _logger; + private ILogger _logger; private readonly IExternalUriConverter _uriConverter; + /// + /// Field name in json format that contains lyric text. + /// private const string _lyricStart = "\"lyrics\""; + // "instrumental":true + private const string _instrumentalStart = "\"instrumental\""; + // "songIsInstrumental":true + private const string _songIsInstrumentalStart = "\"songIsInstrumental\""; + #region Constructors public LyricFindProvider() @@ -67,7 +76,7 @@ protected override SearchResult SearchLyric(Uri uri) if (WebClient == null || Parser == null) { _logger?.LogWarning($"LyricFind. Please set up WebClient and Parser first"); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.LyricFind); } var text = WebClient.Load(uri); return PostProcessLyric(uri, text); @@ -87,7 +96,7 @@ protected override async Task SearchLyricAsync(Uri uri) if (WebClient == null || Parser == null) { _logger?.LogWarning($"LyricFind. Please set up WebClient and Parser first"); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.LyricFind); } var text = await WebClient.LoadAsync(uri); return PostProcessLyric(uri, text); @@ -95,19 +104,28 @@ protected override async Task SearchLyricAsync(Uri uri) #endregion + public override void WithLogger(ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + } + private SearchResult PostProcessLyric(Uri uri, string text) { if (string.IsNullOrEmpty(text)) { - _logger?.LogWarning($"LyricFind. Text is empty for {uri}"); - return new SearchResult(); + _logger?.LogWarning($"LyricFind. Text is empty for Uri: [{uri}]"); + return new SearchResult(Models.ExternalProviderType.LyricFind); } var startIndex = text.IndexOf(_lyricStart); if (startIndex <= 0) { - _logger?.LogWarning($"LyricFind. Can't find lyrics for {uri}"); - return new SearchResult(); + // In case of instrumental song it could not contains lyric field. + if (IsInstumentalLyric(text)) + return new SearchResult(Models.ExternalProviderType.LyricFind).AddInstrumental(true); + + _logger?.LogWarning($"LyricFind. Can't find lyrics for Uri: [{uri}]"); + return new SearchResult(Models.ExternalProviderType.LyricFind); } // Trim the beginning of the text to the lyrics @@ -121,13 +139,39 @@ private SearchResult PostProcessLyric(Uri uri, string text) int endOfLyricInJson = Math.Max(Math.Min(endOfFieldValue, endOfJsonObject), -1); if (endOfLyricInJson < 0) { - _logger?.LogWarning($"LyricFind. Can't parse lyrics for {uri}"); - return new SearchResult(); + // In case of instrumental song it could not contains lyric field. + if (IsInstumentalLyric(text)) + return new SearchResult(Models.ExternalProviderType.LyricFind).AddInstrumental(true); + + _logger?.LogWarning($"LyricFind. Can't parse lyrics for Uri: [{uri}]"); + return new SearchResult(Models.ExternalProviderType.LyricFind); } string result = Parser.Parse(text.Substring(start, endOfLyricInJson - start)); return new SearchResult(result, Models.ExternalProviderType.LyricFind); } + + /// + /// Check if lyric text contains instrumental flag. + /// + private bool IsInstumentalLyric(string text) + { + return TryReturnBooleanFieldValue(text, _instrumentalStart) + || TryReturnBooleanFieldValue(text, _songIsInstrumentalStart); + } + + /// + /// Try to find and return the fielad value as boolean. Pattern: [:true(or false)]. + /// In case if fieldName is not found returns false. + /// + private bool TryReturnBooleanFieldValue(string text, string fieldName) + { + var startIndex = text.IndexOf(fieldName); + if (startIndex <= 0) + return false; + var fieldValue = text.Substring(startIndex + fieldName.Length + 1, 5); + return fieldValue.IndexOf("true", StringComparison.OrdinalIgnoreCase) >= 0; + } } } diff --git a/LyricsScraperNET/Providers/Musixmatch/MusixmatchProvider.cs b/LyricsScraperNET/Providers/Musixmatch/MusixmatchProvider.cs index 01747fa..8a5b288 100644 --- a/LyricsScraperNET/Providers/Musixmatch/MusixmatchProvider.cs +++ b/LyricsScraperNET/Providers/Musixmatch/MusixmatchProvider.cs @@ -1,4 +1,5 @@ -using LyricsScraperNET.Helpers; +using LyricsScraperNET.Extensions; +using LyricsScraperNET.Helpers; using LyricsScraperNET.Models.Responses; using LyricsScraperNET.Providers.Abstract; using Microsoft.Extensions.Caching.Memory; @@ -17,7 +18,7 @@ namespace LyricsScraperNET.Providers.Musixmatch { public sealed class MusixmatchProvider : ExternalProviderBase { - private readonly ILogger _logger; + private ILogger _logger; // Musixmatch Token memory cache private static readonly IMemoryCache _memoryCache; @@ -80,7 +81,7 @@ public MusixmatchProvider(IOptionsSnapshot options) // TODO: search by uri from the site. Example: https://www.musixmatch.com/lyrics/Parkway-Drive/Idols-and-Anchors protected override SearchResult SearchLyric(Uri uri) { - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.Musixmatch); } protected override SearchResult SearchLyric(string artist, string song) @@ -97,14 +98,19 @@ protected override SearchResult SearchLyric(string artist, string song) if (trackId != null) { Lyrics lyrics = client.GetTrackLyrics(trackId.Value); - return lyrics.Instrumental != 1 - ? new SearchResult(lyrics.LyricsBody, Models.ExternalProviderType.Musixmatch) - : new SearchResult(); // lyrics.LyricsBody is null when the track is instrumental + + // lyrics.LyricsBody is null when the track is instrumental + if (lyrics.Instrumental != 1) + return new SearchResult(lyrics.LyricsBody, Models.ExternalProviderType.Musixmatch); + + // Instrumental music without lyric + return new SearchResult(Models.ExternalProviderType.Musixmatch) + .AddInstrumental(true); } else { _logger?.LogWarning($"Musixmatch. Can't find any information about artist {artist} and song {song}"); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.Musixmatch); } } catch (MusixmatchRequestException requestException) when (requestException.StatusCode == StatusCode.AuthFailed) @@ -113,7 +119,7 @@ protected override SearchResult SearchLyric(string artist, string song) regenerateToken = true; } } - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.Musixmatch); } #endregion @@ -123,7 +129,7 @@ protected override SearchResult SearchLyric(string artist, string song) // TODO: search by uri from the site. Example: https://www.musixmatch.com/lyrics/Parkway-Drive/Idols-and-Anchors protected override Task SearchLyricAsync(Uri uri) { - return Task.FromResult(new SearchResult()); + return Task.FromResult(new SearchResult(Models.ExternalProviderType.Musixmatch)); } protected override async Task SearchLyricAsync(string artist, string song) @@ -141,14 +147,19 @@ protected override async Task SearchLyricAsync(string artist, stri if (trackId != null) { Lyrics lyrics = await client.GetTrackLyricsAsync(trackId.Value); - return lyrics.Instrumental != 1 - ? new SearchResult(lyrics.LyricsBody, Models.ExternalProviderType.Musixmatch) - : new SearchResult(); // lyrics.LyricsBody is null when the track is instrumental + + // lyrics.LyricsBody is null when the track is instrumental + if (lyrics.Instrumental != 1) + return new SearchResult(lyrics.LyricsBody, Models.ExternalProviderType.Musixmatch); + + // Instrumental music without lyric + return new SearchResult(Models.ExternalProviderType.Musixmatch) + .AddInstrumental(true); } else { _logger?.LogWarning($"Musixmatch. Can't find any information about artist {artist} and song {song}"); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.Musixmatch); } } catch (MusixmatchRequestException requestException) when (requestException.StatusCode == StatusCode.AuthFailed) @@ -157,11 +168,16 @@ protected override async Task SearchLyricAsync(string artist, stri regenerateToken = true; } } - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.Musixmatch); } #endregion + public override void WithLogger(ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + } + private MusixmatchClient GetMusixmatchClient(bool regenerateToken = false) { // TODO: uncomment after the fix of https://github.com/Eimaen/MusixmatchClientLib/issues/21 diff --git a/LyricsScraperNET/Providers/SongLyrics/SongLyricsProvider.cs b/LyricsScraperNET/Providers/SongLyrics/SongLyricsProvider.cs index f517b5a..cb30da4 100644 --- a/LyricsScraperNET/Providers/SongLyrics/SongLyricsProvider.cs +++ b/LyricsScraperNET/Providers/SongLyrics/SongLyricsProvider.cs @@ -1,4 +1,5 @@ using HtmlAgilityPack; +using LyricsScraperNET.Extensions; using LyricsScraperNET.Helpers; using LyricsScraperNET.Models.Responses; using LyricsScraperNET.Network; @@ -13,7 +14,7 @@ namespace LyricsScraperNET.Providers.SongLyrics { public sealed class SongLyricsProvider : ExternalProviderBase { - private readonly ILogger _logger; + private ILogger _logger; private readonly IExternalUriConverter _uriConverter; @@ -21,6 +22,11 @@ public sealed class SongLyricsProvider : ExternalProviderBase private const string NotExistLyricPattern = "We do not have the lyrics for (.*) yet."; + /// + /// For instrumental songs, the text "[Instrumental]" is returned in the songLyricsDiv + /// + private const string InstrumentalLyricText = "Instrumental"; + #region Constructors public SongLyricsProvider() @@ -59,7 +65,6 @@ public SongLyricsProvider(IOptionsSnapshot options) public override IExternalProviderOptions Options { get; } - #region Sync protected override SearchResult SearchLyric(string artist, string song) @@ -72,7 +77,7 @@ protected override SearchResult SearchLyric(Uri uri) if (WebClient == null) { _logger?.LogWarning($"SongLyrics. Please set up WebClient first"); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.SongLyrics); } var htmlPageBody = WebClient.Load(uri); return GetParsedLyricFromHtmlPageBody(uri, htmlPageBody); @@ -80,7 +85,6 @@ protected override SearchResult SearchLyric(Uri uri) #endregion - #region Async protected override async Task SearchLyricAsync(string artist, string song) @@ -93,7 +97,7 @@ protected override async Task SearchLyricAsync(Uri uri) if (WebClient == null) { _logger?.LogWarning($"SongLyrics. Please set up WebClient first"); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.SongLyrics); } var htmlPageBody = await WebClient.LoadAsync(uri); return GetParsedLyricFromHtmlPageBody(uri, htmlPageBody); @@ -101,13 +105,17 @@ protected override async Task SearchLyricAsync(Uri uri) #endregion + public override void WithLogger(ILoggerFactory loggerFactory) + { + _logger = loggerFactory.CreateLogger(); + } private SearchResult GetParsedLyricFromHtmlPageBody(Uri uri, string htmlPageBody) { if (string.IsNullOrEmpty(htmlPageBody)) { - _logger?.LogWarning($"SongLyrics. Text is empty for {uri}"); - return new SearchResult(); + _logger?.LogWarning($"SongLyrics. Text is empty for Uri: [{uri}]"); + return new SearchResult(Models.ExternalProviderType.SongLyrics); } var htmlDocument = new HtmlDocument(); @@ -117,16 +125,22 @@ private SearchResult GetParsedLyricFromHtmlPageBody(Uri uri, string htmlPageBody if (lyricsContainerNode == null) { - _logger?.LogWarning($"SongLyrics. Can't find lyrics for {uri}"); - return new SearchResult(); + _logger?.LogWarning($"SongLyrics. Can't find lyrics for Uri: [{uri}]"); + return new SearchResult(Models.ExternalProviderType.SongLyrics); } + // Check if lyric not exist on site yet if (Regex.IsMatch(lyricsContainerNode.InnerText, NotExistLyricPattern, RegexOptions.IgnoreCase)) { _logger?.LogDebug($"SongLyrics. Returns empty result: \"{lyricsContainerNode.InnerText}\""); - return new SearchResult(); + return new SearchResult(Models.ExternalProviderType.SongLyrics); } + // Check if lyric is instrumental + if (string.Equals(lyricsContainerNode.InnerText, InstrumentalLyricText, StringComparison.OrdinalIgnoreCase) + || string.Equals(lyricsContainerNode.InnerText, $"[{InstrumentalLyricText}]", StringComparison.OrdinalIgnoreCase)) + return new SearchResult(Models.ExternalProviderType.SongLyrics).AddInstrumental(true); + return new SearchResult(lyricsContainerNode.InnerText, Models.ExternalProviderType.SongLyrics); } } diff --git a/Tests/LyricsScraperNET.IntegrationTest/LyricsScraperNET.IntegrationTest.csproj b/Tests/LyricsScraperNET.IntegrationTest/LyricsScraperNET.IntegrationTest.csproj index 9bb552d..ce0eff4 100644 --- a/Tests/LyricsScraperNET.IntegrationTest/LyricsScraperNET.IntegrationTest.csproj +++ b/Tests/LyricsScraperNET.IntegrationTest/LyricsScraperNET.IntegrationTest.csproj @@ -34,34 +34,46 @@ PreserveNewest + + PreserveNewest + PreserveNewest + + PreserveNewest + PreserveNewest - + + PreserveNewest + + PreserveNewest PreserveNewest - + PreserveNewest PreserveNewest - + + PreserveNewest + + PreserveNewest - + PreserveNewest PreserveNewest - + PreserveNewest diff --git a/Tests/LyricsScraperNET.IntegrationTest/Properties/launchSettings.json b/Tests/LyricsScraperNET.IntegrationTest/Properties/launchSettings.json deleted file mode 100644 index 33504c9..0000000 --- a/Tests/LyricsScraperNET.IntegrationTest/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "WSL": { - "commandName": "WSL2", - "distributionName": "" - } - } -} \ No newline at end of file diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/AZLyrics/AZLyricsProviderTest.cs b/Tests/LyricsScraperNET.IntegrationTest/Providers/AZLyrics/AZLyricsProviderTest.cs index ea8b49a..2ae5f40 100644 --- a/Tests/LyricsScraperNET.IntegrationTest/Providers/AZLyrics/AZLyricsProviderTest.cs +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/AZLyrics/AZLyricsProviderTest.cs @@ -11,8 +11,8 @@ namespace LyricsScraperNET.IntegrationTest.Providers.AZLyrics public class AZLyricsProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\AZLyrics\\test_data.json")] - public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\AZLyrics\\lyric_test_data.json")] + public void SearchLyric_IntegrationDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new AZLyricsProvider(); diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/AZLyrics/test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/AZLyrics/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.IntegrationTest/Providers/AZLyrics/test_data.json rename to Tests/LyricsScraperNET.IntegrationTest/Providers/AZLyrics/lyric_test_data.json diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/GeniusProviderTest.cs b/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/GeniusProviderTest.cs index fce24f2..253ce1a 100644 --- a/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/GeniusProviderTest.cs +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/GeniusProviderTest.cs @@ -11,8 +11,8 @@ namespace LyricsScraperNET.IntegrationTest.Providers.Genius public class GeniusProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\Genius\\test_data.json")] - public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\Genius\\lyric_test_data.json")] + public void SearchLyric_IntegrationDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new GeniusProvider(); @@ -28,6 +28,27 @@ public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); Assert.Equal(ExternalProviderType.Genius, searchResult.ExternalProviderType); Assert.Equal(testData.LyricResultData.Replace("\r\n", "\n"), searchResult.LyricText.Replace("\r\n", "\n")); + Assert.False(searchResult.Instrumental); + } + + [Theory] + [MemberData(nameof(GetTestData), parameters: "Providers\\Genius\\instrumental_test_data.json")] + public void SearchLyric_UnitDynamicData_Instrumental(LyricsTestData testData) + { + // Arrange + var lyricsClient = new GeniusProvider(); + SearchRequest searchRequest = CreateSearchRequest(testData); + + // Act + var searchResult = lyricsClient.SearchLyric(searchRequest); + + // Assert + Assert.NotNull(searchResult); + Assert.True(searchResult.IsEmpty()); + Assert.Equal(ResponseStatusCode.Success, searchResult.ResponseStatusCode); + Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); + Assert.Equal(ExternalProviderType.Genius, searchResult.ExternalProviderType); + Assert.True(searchResult.Instrumental); } } } diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/instrumental_test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/instrumental_test_data.json new file mode 100644 index 0000000..0d39242 --- /dev/null +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/instrumental_test_data.json @@ -0,0 +1,8 @@ +[ + { + "LyricResultPath": null, + "ArtistName": "Rush", + "SongName": "YYZ", + "SongUri": null + } +] \ No newline at end of file diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/test_data.json rename to Tests/LyricsScraperNET.IntegrationTest/Providers/Genius/lyric_test_data.json diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/LyricFindProviderTest.cs b/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/LyricFindProviderTest.cs index e0fcb4e..b03bc09 100644 --- a/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/LyricFindProviderTest.cs +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/LyricFindProviderTest.cs @@ -11,8 +11,8 @@ namespace LyricsScraperNET.IntegrationTest.Providers.LyricFind public class LyricFindProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\LyricFind\\test_data.json")] - public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\LyricFind\\lyric_test_data.json")] + public void SearchLyric_IntegrationDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new LyricFindProvider(); @@ -28,6 +28,27 @@ public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); Assert.Equal(ExternalProviderType.LyricFind, searchResult.ExternalProviderType); Assert.Equal(testData.LyricResultData.Replace("\r\n", "\n"), searchResult.LyricText.Replace("\r\n", "\n")); + Assert.False(searchResult.Instrumental); + } + + [Theory] + [MemberData(nameof(GetTestData), parameters: "Providers\\LyricFind\\instrumental_test_data.json")] + public void SearchLyric_IntegrationDynamicData_Instrumental(LyricsTestData testData) + { + // Arrange + var lyricsClient = new LyricFindProvider(); + SearchRequest searchRequest = CreateSearchRequest(testData); + + // Act + var searchResult = lyricsClient.SearchLyric(searchRequest); + + // Assert + Assert.NotNull(searchResult); + Assert.True(searchResult.IsEmpty()); + Assert.Equal(ResponseStatusCode.Success, searchResult.ResponseStatusCode); + Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); + Assert.Equal(ExternalProviderType.LyricFind, searchResult.ExternalProviderType); + Assert.True(searchResult.Instrumental); } } } diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/instrumental_test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/instrumental_test_data.json new file mode 100644 index 0000000..0d39242 --- /dev/null +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/instrumental_test_data.json @@ -0,0 +1,8 @@ +[ + { + "LyricResultPath": null, + "ArtistName": "Rush", + "SongName": "YYZ", + "SongUri": null + } +] \ No newline at end of file diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/test_data.json rename to Tests/LyricsScraperNET.IntegrationTest/Providers/LyricFind/lyric_test_data.json diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/MusixmatchProviderTest.cs b/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/MusixmatchProviderTest.cs index 28b0e12..07aa554 100644 --- a/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/MusixmatchProviderTest.cs +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/MusixmatchProviderTest.cs @@ -11,8 +11,8 @@ namespace LyricsScraperNET.IntegrationTest.Providers.Musixmatch public class MusixmatchProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\Musixmatch\\test_data.json")] - public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\Musixmatch\\lyric_test_data.json")] + public void SearchLyric_IntegrationDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new MusixmatchProvider(); @@ -28,6 +28,27 @@ public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); Assert.Equal(ExternalProviderType.Musixmatch, searchResult.ExternalProviderType); Assert.Equal(testData.LyricResultData.Replace("\r\n", "\n"), searchResult.LyricText); + Assert.False(searchResult.Instrumental); + } + + [Theory] + [MemberData(nameof(GetTestData), parameters: "Providers\\Musixmatch\\instrumental_test_data.json")] + public void SearchLyric_IntegrationDynamicData_Instrumental(LyricsTestData testData) + { + // Arrange + var lyricsClient = new MusixmatchProvider(); + SearchRequest searchRequest = CreateSearchRequest(testData); + + // Act + var searchResult = lyricsClient.SearchLyric(searchRequest); + + // Assert + Assert.NotNull(searchResult); + Assert.True(searchResult.IsEmpty()); + Assert.Equal(ResponseStatusCode.Success, searchResult.ResponseStatusCode); + Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); + Assert.Equal(ExternalProviderType.Musixmatch, searchResult.ExternalProviderType); + Assert.True(searchResult.Instrumental); } } } diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/instrumental_test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/instrumental_test_data.json new file mode 100644 index 0000000..0d39242 --- /dev/null +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/instrumental_test_data.json @@ -0,0 +1,8 @@ +[ + { + "LyricResultPath": null, + "ArtistName": "Rush", + "SongName": "YYZ", + "SongUri": null + } +] \ No newline at end of file diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/test_data.json rename to Tests/LyricsScraperNET.IntegrationTest/Providers/Musixmatch/lyric_test_data.json diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/SongLyricsProviderTest.cs b/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/SongLyricsProviderTest.cs index 791c10b..0cd6391 100644 --- a/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/SongLyricsProviderTest.cs +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/SongLyricsProviderTest.cs @@ -11,8 +11,8 @@ namespace LyricsScraperNET.IntegrationTest.Providers.SongLyrics public class SongLyricsProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\SongLyrics\\test_data.json")] - public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\SongLyrics\\lyric_test_data.json")] + public void SearchLyric_IntegrationDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new SongLyricsProvider(); @@ -28,6 +28,27 @@ public void SearchLyric_IntegrationDynamicData_AreEqual(LyricsTestData testData) Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); Assert.Equal(ExternalProviderType.SongLyrics, searchResult.ExternalProviderType); Assert.Equal(testData.LyricResultData.Replace("\r\n", "\n"), searchResult.LyricText.Replace("\r\n", "\n")); + Assert.False(searchResult.Instrumental); + } + + [Theory] + [MemberData(nameof(GetTestData), parameters: "Providers\\SongLyrics\\instrumental_test_data.json")] + public void SearchLyric_IntegrationDynamicData_Instrumental(LyricsTestData testData) + { + // Arrange + var lyricsClient = new SongLyricsProvider(); + SearchRequest searchRequest = CreateSearchRequest(testData); + + // Act + var searchResult = lyricsClient.SearchLyric(searchRequest); + + // Assert + Assert.NotNull(searchResult); + Assert.True(searchResult.IsEmpty()); + Assert.Equal(ResponseStatusCode.Success, searchResult.ResponseStatusCode); + Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); + Assert.Equal(ExternalProviderType.SongLyrics, searchResult.ExternalProviderType); + Assert.True(searchResult.Instrumental); } } } diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/instrumental_test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/instrumental_test_data.json new file mode 100644 index 0000000..0d39242 --- /dev/null +++ b/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/instrumental_test_data.json @@ -0,0 +1,8 @@ +[ + { + "LyricResultPath": null, + "ArtistName": "Rush", + "SongName": "YYZ", + "SongUri": null + } +] \ No newline at end of file diff --git a/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/test_data.json b/Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/test_data.json rename to Tests/LyricsScraperNET.IntegrationTest/Providers/SongLyrics/lyric_test_data.json diff --git a/Tests/LyricsScraperNET.UnitTest/LyricsScraperClientTests.cs b/Tests/LyricsScraperNET.UnitTest/LyricsScraperClientTests.cs index 0b128a4..aae6189 100644 --- a/Tests/LyricsScraperNET.UnitTest/LyricsScraperClientTests.cs +++ b/Tests/LyricsScraperNET.UnitTest/LyricsScraperClientTests.cs @@ -34,10 +34,12 @@ public async void SearchLyric_WithDisabledClient_ShouldReturnEmptySearchResult() Assert.True(searchResult.IsEmpty()); Assert.Equal(ResponseStatusCode.NoDataFound, searchResult.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.ExternalProvidersAreDisabled, searchResult.ResponseMessage); + Assert.False(searchResult.Instrumental); Assert.NotNull(searchResultAsync); Assert.True(searchResultAsync.IsEmpty()); Assert.Equal(ResponseStatusCode.NoDataFound, searchResultAsync.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.ExternalProvidersAreDisabled, searchResultAsync.ResponseMessage); + Assert.False(searchResultAsync.Instrumental); } [Fact] @@ -57,10 +59,12 @@ public async void SearchLyric_DefaultClient_ShouldReturnEmptySearchResult() Assert.True(searchResult.IsEmpty()); Assert.Equal(ResponseStatusCode.NoDataFound, searchResult.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.ExternalProvidersListIsEmpty, searchResult.ResponseMessage); + Assert.False(searchResult.Instrumental); Assert.NotNull(searchResultAsync); Assert.True(searchResultAsync.IsEmpty()); Assert.Equal(ResponseStatusCode.NoDataFound, searchResultAsync.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.ExternalProvidersListIsEmpty, searchResultAsync.ResponseMessage); + Assert.False(searchResultAsync.Instrumental); } [Theory] @@ -85,11 +89,13 @@ public async void SearchLyric_MalformedArtistAndSongSearchRequest_ShouldReturnBa Assert.Equal(ExternalProviderType.None, searchResult.ExternalProviderType); Assert.Equal(ResponseStatusCode.BadRequest, searchResult.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.ArtistAndSongSearchRequestFieldsAreEmpty, searchResult.ResponseMessage); + Assert.False(searchResult.Instrumental); Assert.NotNull(searchResultAsync); Assert.True(searchResultAsync.IsEmpty()); Assert.Equal(ExternalProviderType.None, searchResultAsync.ExternalProviderType); Assert.Equal(ResponseStatusCode.BadRequest, searchResultAsync.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.ArtistAndSongSearchRequestFieldsAreEmpty, searchResultAsync.ResponseMessage); + Assert.False(searchResultAsync.Instrumental); } [Theory] @@ -111,11 +117,13 @@ public async void SearchLyric_MalformedUriSearchRequest_ShouldReturnBadRequestSt Assert.Equal(ExternalProviderType.None, searchResult.ExternalProviderType); Assert.Equal(ResponseStatusCode.BadRequest, searchResult.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.UriSearchRequestFieldsAreEmpty, searchResult.ResponseMessage); + Assert.False(searchResult.Instrumental); Assert.NotNull(searchResultAsync); Assert.True(searchResultAsync.IsEmpty()); Assert.Equal(ExternalProviderType.None, searchResultAsync.ExternalProviderType); Assert.Equal(ResponseStatusCode.BadRequest, searchResultAsync.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.UriSearchRequestFieldsAreEmpty, searchResultAsync.ResponseMessage); + Assert.False(searchResultAsync.Instrumental); } [Fact] @@ -135,11 +143,13 @@ public async void SearchLyric_EmptySearchRequest_ShouldReturnBadRequestStatus() Assert.Equal(ExternalProviderType.None, searchResult.ExternalProviderType); Assert.Equal(ResponseStatusCode.BadRequest, searchResult.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.SearchRequestIsEmpty, searchResult.ResponseMessage); + Assert.False(searchResult.Instrumental); Assert.NotNull(searchResultAsync); Assert.True(searchResultAsync.IsEmpty()); Assert.Equal(ExternalProviderType.None, searchResultAsync.ExternalProviderType); Assert.Equal(ResponseStatusCode.BadRequest, searchResultAsync.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.SearchRequestIsEmpty, searchResultAsync.ResponseMessage); + Assert.False(searchResultAsync.Instrumental); } [Fact] @@ -159,11 +169,13 @@ public async void SearchLyric_ProviderWithEmptyResult_ShouldReturnNotFoundStatus Assert.Equal(ExternalProviderType.None, searchResult.ExternalProviderType); Assert.Equal(ResponseStatusCode.NoDataFound, searchResult.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.NotFoundLyric, searchResult.ResponseMessage); + Assert.False(searchResult.Instrumental); Assert.NotNull(searchResultAsync); Assert.True(searchResultAsync.IsEmpty()); Assert.Equal(ExternalProviderType.None, searchResultAsync.ExternalProviderType); Assert.Equal(ResponseStatusCode.NoDataFound, searchResultAsync.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.NotFoundLyric, searchResultAsync.ResponseMessage); + Assert.False(searchResultAsync.Instrumental); } [Fact] @@ -183,11 +195,13 @@ public async void SearchLyric_ProviderNotSpecifiedForRequest_ShouldReturnNotFoun Assert.Equal(ExternalProviderType.None, searchResult.ExternalProviderType); Assert.Equal(ResponseStatusCode.BadRequest, searchResult.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.ExternalProviderForRequestNotSpecified, searchResult.ResponseMessage); + Assert.False(searchResult.Instrumental); Assert.NotNull(searchResultAsync); Assert.True(searchResultAsync.IsEmpty()); Assert.Equal(ExternalProviderType.None, searchResultAsync.ExternalProviderType); Assert.Equal(ResponseStatusCode.BadRequest, searchResultAsync.ResponseStatusCode); Assert.Equal(Constants.ResponseMessages.ExternalProviderForRequestNotSpecified, searchResultAsync.ResponseMessage); + Assert.False(searchResultAsync.Instrumental); } [Fact] diff --git a/Tests/LyricsScraperNET.UnitTest/LyricsScraperNET.UnitTest.csproj b/Tests/LyricsScraperNET.UnitTest/LyricsScraperNET.UnitTest.csproj index 82547a7..7c3b142 100644 --- a/Tests/LyricsScraperNET.UnitTest/LyricsScraperNET.UnitTest.csproj +++ b/Tests/LyricsScraperNET.UnitTest/LyricsScraperNET.UnitTest.csproj @@ -31,13 +31,19 @@ + + PreserveNewest + + + PreserveNewest + PreserveNewest PreserveNewest - + PreserveNewest @@ -46,7 +52,13 @@ PreserveNewest - + + PreserveNewest + + + PreserveNewest + + PreserveNewest @@ -55,7 +67,13 @@ PreserveNewest - + + PreserveNewest + + + PreserveNewest + + PreserveNewest @@ -64,7 +82,7 @@ PreserveNewest - + PreserveNewest diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/AZLyrics/AZLyricsProviderTest.cs b/Tests/LyricsScraperNET.UnitTest/Providers/AZLyrics/AZLyricsProviderTest.cs index 19e76e4..65052e5 100644 --- a/Tests/LyricsScraperNET.UnitTest/Providers/AZLyrics/AZLyricsProviderTest.cs +++ b/Tests/LyricsScraperNET.UnitTest/Providers/AZLyrics/AZLyricsProviderTest.cs @@ -12,8 +12,8 @@ namespace LyricsScraperNET.UnitTest.Providers.AZLyrics public class AZLyricsProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\AZLyrics\\test_data.json")] - public void SearchLyric_UnitDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\AZLyrics\\lyric_test_data.json")] + public void SearchLyric_UnitDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new AZLyricsProvider(); diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/AZLyrics/test_data.json b/Tests/LyricsScraperNET.UnitTest/Providers/AZLyrics/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.UnitTest/Providers/AZLyrics/test_data.json rename to Tests/LyricsScraperNET.UnitTest/Providers/AZLyrics/lyric_test_data.json diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/Genius/GeniusProviderTest.cs b/Tests/LyricsScraperNET.UnitTest/Providers/Genius/GeniusProviderTest.cs index 535d053..4cb7b5b 100644 --- a/Tests/LyricsScraperNET.UnitTest/Providers/Genius/GeniusProviderTest.cs +++ b/Tests/LyricsScraperNET.UnitTest/Providers/Genius/GeniusProviderTest.cs @@ -12,8 +12,8 @@ namespace LyricsScraperNET.UnitTest.Providers.Genius public class GeniusProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\Genius\\test_data.json")] - public void SearchLyric_UnitDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\Genius\\lyric_test_data.json")] + public void SearchLyric_UnitDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new GeniusProvider(); @@ -26,10 +26,34 @@ public void SearchLyric_UnitDynamicData_AreEqual(LyricsTestData testData) // Assert Assert.NotNull(searchResult); + Assert.False(searchResult.IsEmpty()); Assert.Equal(ResponseStatusCode.Success, searchResult.ResponseStatusCode); Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); Assert.Equal(ExternalProviderType.Genius, searchResult.ExternalProviderType); Assert.Equal(testData.LyricResultData.Replace("\r\n", "\n"), searchResult.LyricText.Replace("\r\n", "\n")); + Assert.False(searchResult.Instrumental); + } + + [Theory] + [MemberData(nameof(GetTestData), parameters: "Providers\\Genius\\instrumental_test_data.json")] + public void SearchLyric_UnitDynamicData_Instrumental(LyricsTestData testData) + { + // Arrange + var lyricsClient = new GeniusProvider(); + lyricsClient.ConfigureExternalProvider(testData); + + SearchRequest searchRequest = CreateSearchRequest(testData); + + // Act + var searchResult = lyricsClient.SearchLyric(searchRequest); + + // Assert + Assert.NotNull(searchResult); + Assert.True(searchResult.IsEmpty()); + Assert.Equal(ResponseStatusCode.Success, searchResult.ResponseStatusCode); + Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); + Assert.Equal(ExternalProviderType.Genius, searchResult.ExternalProviderType); + Assert.True(searchResult.Instrumental); } } } diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/Genius/Resources/Instrumental_HtmlPage_01.txt b/Tests/LyricsScraperNET.UnitTest/Providers/Genius/Resources/Instrumental_HtmlPage_01.txt new file mode 100644 index 0000000..e2c386e --- /dev/null +++ b/Tests/LyricsScraperNET.UnitTest/Providers/Genius/Resources/Instrumental_HtmlPage_01.txt @@ -0,0 +1,967 @@ + + + + Rush – YYZ Lyrics | Genius Lyrics + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

This song is an instrumental

How to Format Lyrics:

  • Type out all lyrics, even repeating song parts like the chorus
  • Lyrics should be broken down into individual lines
  • Use section headers above different song parts like [Verse], [Chorus], etc.
  • Use italics (<i>lyric</i>) and bold (<b>lyric</b>) to distinguish between different vocalists in the same song part
  • If you don’t understand a lyric, use [?]

To learn more, check out our transcription guide or visit our transcribers forum

About

Genius Annotation

An instrumental interlude named for Rush’s local airport, Toronto’s Pearson International, which is represented by the code YYZ, hence the use of the title in morse code (sort of) as a motif throughout the song. This song has become legendary among Rush fans for the insane and lengthy solos drummer Neil Peart often adds when it’s performed in concert.

Q&A

Find answers to frequently asked questions about the song and explore its deeper meaning

Comments
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/Genius/instrumental_test_data.json b/Tests/LyricsScraperNET.UnitTest/Providers/Genius/instrumental_test_data.json new file mode 100644 index 0000000..ed49ab0 --- /dev/null +++ b/Tests/LyricsScraperNET.UnitTest/Providers/Genius/instrumental_test_data.json @@ -0,0 +1,9 @@ +[ + { + "LyricPagePath": "Providers/Genius/Resources/Instrumental_HtmlPage_01.txt", + "LyricResultPath": null, + "ArtistName": null, + "SongName": null, + "SongUri": "https://genius.com/Rush-yyz-lyrics" + } +] \ No newline at end of file diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/Genius/test_data.json b/Tests/LyricsScraperNET.UnitTest/Providers/Genius/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.UnitTest/Providers/Genius/test_data.json rename to Tests/LyricsScraperNET.UnitTest/Providers/Genius/lyric_test_data.json diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/LyricFindProviderTest.cs b/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/LyricFindProviderTest.cs index ec8746c..d99a36a 100644 --- a/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/LyricFindProviderTest.cs +++ b/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/LyricFindProviderTest.cs @@ -12,8 +12,8 @@ namespace LyricsScraperNET.UnitTest.Providers.LyricFind public class LyricFindProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\LyricFind\\test_data.json")] - public void SearchLyric_UnitDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\LyricFind\\lyric_test_data.json")] + public void SearchLyric_UnitDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new LyricFindProvider(); @@ -30,6 +30,29 @@ public void SearchLyric_UnitDynamicData_AreEqual(LyricsTestData testData) Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); Assert.Equal(ExternalProviderType.LyricFind, searchResult.ExternalProviderType); Assert.Equal(testData.LyricResultData.Replace("\r\n", "\n"), searchResult.LyricText.Replace("\r\n", "\n")); + Assert.False(searchResult.Instrumental); + } + + [Theory] + [MemberData(nameof(GetTestData), parameters: "Providers\\LyricFind\\instrumental_test_data.json")] + public void SearchLyric_UnitDynamicData_Instrumental(LyricsTestData testData) + { + // Arrange + var lyricsClient = new LyricFindProvider(); + lyricsClient.ConfigureExternalProvider(testData); + + SearchRequest searchRequest = CreateSearchRequest(testData); + + // Act + var searchResult = lyricsClient.SearchLyric(searchRequest); + + // Assert + Assert.NotNull(searchResult); + Assert.True(searchResult.IsEmpty()); + Assert.Equal(ResponseStatusCode.Success, searchResult.ResponseStatusCode); + Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); + Assert.Equal(ExternalProviderType.LyricFind, searchResult.ExternalProviderType); + Assert.True(searchResult.Instrumental); } } } diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/Resources/Instrumental_HtmlPage_01.txt b/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/Resources/Instrumental_HtmlPage_01.txt new file mode 100644 index 0000000..ad53c9e --- /dev/null +++ b/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/Resources/Instrumental_HtmlPage_01.txt @@ -0,0 +1,17 @@ +Lyrics | Rush | YYZ
ChartsGenres
Add Song
logoLyricFind
Lyric cover art as blurred background
Lyric cover art

YYZ

Moving Pictures

Rush

1981

Apple Music logo
Apple Music logo

Deezer logo
Deezer logo

Spotify logo
Spotify logo
Lyric cover art

Moving Pictures

1981

From This Artist
\ No newline at end of file diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/instrumental_test_data.json b/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/instrumental_test_data.json new file mode 100644 index 0000000..f9db80f --- /dev/null +++ b/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/instrumental_test_data.json @@ -0,0 +1,9 @@ +[ + { + "LyricPagePath": "Providers/LyricFind/Resources/Instrumental_HtmlPage_01.txt", + "LyricResultPath": null, + "ArtistName": "Rush", + "SongName": "YYZ", + "SongUri": null + } +] \ No newline at end of file diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/test_data.json b/Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/test_data.json rename to Tests/LyricsScraperNET.UnitTest/Providers/LyricFind/lyric_test_data.json diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/Resources/Instrumental_HtmlPage_01.txt b/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/Resources/Instrumental_HtmlPage_01.txt new file mode 100644 index 0000000..814902c --- /dev/null +++ b/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/Resources/Instrumental_HtmlPage_01.txt @@ -0,0 +1,1092 @@ + + + + RUSH - YYZ LYRICS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ +
+
+ + 55k + +
+ Like +
+ + +
+
+ +
+
+ + + + + +
+ + + + + + + + + + + + + +
+ + + +
+
+
+ Lead RIFFs: +
+
+ +
+ +
+
Bad selection
+
+

Cannot annotate a non-flat selection. Make sure your selection + starts and ends within the same node.

+
+ (example of bad selection): This is bold + text and this is normal text. +
+
+ (example of good selection): This is bold + text and this is normal text. +
+
+
+ +
+
Bad selection
+
+

An annotation cannot contain another annotation.

+
+
+ + + + + +
+
+ + +
+
Anonymous
+ + + + +
+ + +
+ + +
+ +
+ + +
+
+ + +
+
+ Really delete this comment? +
+ + +
+
+
+ + +
+ +
+ +
+ + +
+ + + +
+ +
+ + + + +
+ + +
+ + +
+
Anonymous
+ + + + +
+ + +
+ + +
+ +
+ + +
+
+ + +
+
+ Really delete this comment? +
+ + +
+
+
+ +
+ +
+ +
+ + +
+ + + +
+ +
+ +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/SongLyricsProviderTest.cs b/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/SongLyricsProviderTest.cs index b22a8aa..a45daf9 100644 --- a/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/SongLyricsProviderTest.cs +++ b/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/SongLyricsProviderTest.cs @@ -12,8 +12,8 @@ namespace LyricsScraperNET.UnitTest.Providers.SongLyrics public class SongLyricsProviderTest : ProviderTestBase { [Theory] - [MemberData(nameof(GetTestData), parameters: "Providers\\SongLyrics\\test_data.json")] - public void SearchLyric_UnitDynamicData_AreEqual(LyricsTestData testData) + [MemberData(nameof(GetTestData), parameters: "Providers\\SongLyrics\\lyric_test_data.json")] + public void SearchLyric_UnitDynamicData_Success(LyricsTestData testData) { // Arrange var lyricsClient = new SongLyricsProvider(); @@ -30,6 +30,29 @@ public void SearchLyric_UnitDynamicData_AreEqual(LyricsTestData testData) Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); Assert.Equal(ExternalProviderType.SongLyrics, searchResult.ExternalProviderType); Assert.Equal(testData.LyricResultData.Replace("\r\n", "\n"), searchResult.LyricText.Replace("\r\n", "\n")); + Assert.False(searchResult.Instrumental); + } + + [Theory] + [MemberData(nameof(GetTestData), parameters: "Providers\\SongLyrics\\instrumental_test_data.json")] + public void SearchLyric_UnitDynamicData_Instrumental(LyricsTestData testData) + { + // Arrange + var lyricsClient = new SongLyricsProvider(); + lyricsClient.ConfigureExternalProvider(testData); + + SearchRequest searchRequest = CreateSearchRequest(testData); + + // Act + var searchResult = lyricsClient.SearchLyric(searchRequest); + + // Assert + Assert.NotNull(searchResult); + Assert.True(searchResult.IsEmpty()); + Assert.Equal(ResponseStatusCode.Success, searchResult.ResponseStatusCode); + Assert.True(string.IsNullOrEmpty(searchResult.ResponseMessage)); + Assert.Equal(ExternalProviderType.SongLyrics, searchResult.ExternalProviderType); + Assert.True(searchResult.Instrumental); } } } diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/instrumental_test_data.json b/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/instrumental_test_data.json new file mode 100644 index 0000000..cd18b49 --- /dev/null +++ b/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/instrumental_test_data.json @@ -0,0 +1,9 @@ +[ + { + "LyricPagePath": "Providers/SongLyrics/Resources/Instrumental_HtmlPage_01.txt", + "LyricResultPath": null, + "ArtistName": "Rush", + "SongName": "YYZ", + "SongUri": null + } +] \ No newline at end of file diff --git a/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/test_data.json b/Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/lyric_test_data.json similarity index 100% rename from Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/test_data.json rename to Tests/LyricsScraperNET.UnitTest/Providers/SongLyrics/lyric_test_data.json