4 Commits

Author SHA1 Message Date
Ritiek Malhotra
64d54d7943 Retry a few times if Genius returns an invalid response 2020-05-18 17:50:01 +05:30
Ritiek Malhotra
85c12a91ef Call debug statements when fetching lyrics 2020-05-18 16:28:10 +05:30
Ritiek Malhotra
9795d7e9b8 Release v2.0.2 2020-05-18 15:16:00 +05:30
Ritiek Malhotra
bbe43da191 Bugfix: crash when skipping track with -m [Fixes #721] 2020-05-18 15:14:22 +05:30
5 changed files with 37 additions and 12 deletions

View File

@@ -8,6 +8,14 @@ The release dates mentioned follow the format `DD-MM-YYYY`.
## [Unreleased] ## [Unreleased]
## [2.0.3] (Hotfix Release) - 18-05-2020
### Fixed
- Genius would sometimes return invalid lyrics. Retry a few times in such a case.
## [2.0.2] (Hotfix Release) - 18-05-2020
### Fixed
- Skipping tracks with `-m` would crash.
## [2.0.1] (Hotfix Release) - 18-05-2020 ## [2.0.1] (Hotfix Release) - 18-05-2020
### Fixed ### Fixed
- `-o m4a` would always fail. - `-o m4a` would always fail.

View File

@@ -48,14 +48,12 @@ class Genius(LyricBase):
else: else:
return response.read() return response.read()
def _get_lyrics_text(self, html): def _get_lyrics_text(self, paragraph):
""" """
Extracts and returns the lyric content from the provided HTML. Extracts and returns the lyric content from the provided HTML.
""" """
soup = BeautifulSoup(html, "html.parser") if paragraph:
lyrics_paragraph = soup.find("p") return paragraph.get_text()
if lyrics_paragraph:
return lyrics_paragraph.get_text()
else: else:
raise LyricsNotFoundError( raise LyricsNotFoundError(
"The lyrics for this track are yet to be released on Genius." "The lyrics for this track are yet to be released on Genius."
@@ -81,6 +79,7 @@ class Genius(LyricBase):
""" """
encoded_query = urllib.request.quote(query.replace(" ", "+")) encoded_query = urllib.request.quote(query.replace(" ", "+"))
search_url = self.base_search_url + encoded_query search_url = self.base_search_url + encoded_query
logger.debug('Fetching Genius search results from "{}".'.format(search_url))
metadata = self._fetch_search_page(search_url) metadata = self._fetch_search_page(search_url)
lyric_url = None lyric_url = None
@@ -105,6 +104,7 @@ class Genius(LyricBase):
Returns the lyric string for the track best matching the Returns the lyric string for the track best matching the
given query. given query.
""" """
logger.debug('Fetching lyrics for the search query on "{}".'.format(query))
try: try:
lyric_url = self.best_matching_lyric_url_from_query(query) lyric_url = self.best_matching_lyric_url_from_query(query)
except LyricsNotFoundError: except LyricsNotFoundError:
@@ -123,11 +123,29 @@ class Genius(LyricBase):
lyric_url = self.guess_lyric_url_from_artist_and_track(artist, track) lyric_url = self.guess_lyric_url_from_artist_and_track(artist, track)
return self.from_url(lyric_url, linesep, timeout) return self.from_url(lyric_url, linesep, timeout)
def from_url(self, url, linesep="\n", timeout=None): def from_url(self, url, linesep="\n", retries=5, timeout=None):
""" """
Returns the lyric string for the given URL. Returns the lyric string for the given URL.
""" """
logger.debug('Fetching lyric text from "{}".'.format(url))
lyric_html_page = self._fetch_url_page(url, timeout=timeout) lyric_html_page = self._fetch_url_page(url, timeout=timeout)
lyrics = self._get_lyrics_text(lyric_html_page) soup = BeautifulSoup(lyric_html_page, "html.parser")
paragraph = soup.find("p")
# If <p> has a class (like <p class="bla">), then we got an invalid
# response. Retry in such a case.
invalid_response = paragraph.get("class") is not None
to_retry = retries > 0 and invalid_response
if to_retry:
logger.debug(
"Retrying since Genius returned invalid response for search "
"results. Retries left: {retries}.".format(retries=retries)
)
return self.from_url(url, linesep=linesep, retries=retries-1, timeout=timeout)
if invalid_response:
raise LyricsNotFoundError(
'Genius returned invalid response for the search URL "{}".'.format(url)
)
lyrics = self._get_lyrics_text(paragraph)
return lyrics.replace("\n", linesep) return lyrics.replace("\n", linesep)

View File

@@ -53,7 +53,7 @@ class YouTubeSearch:
quoted_query = urllib.request.quote(query) quoted_query = urllib.request.quote(query)
return self.base_search_url.format(quoted_query) return self.base_search_url.format(quoted_query)
def _fetch_response_html(self, url, retries=5): def _fetch_response_html(self, url):
response = urllib.request.urlopen(url) response = urllib.request.urlopen(url)
soup = BeautifulSoup(response.read(), "html.parser") soup = BeautifulSoup(response.read(), "html.parser")
return soup return soup
@@ -119,12 +119,11 @@ class YouTubeSearch:
videos = self._fetch_search_results(html, limit=limit) videos = self._fetch_search_results(html, limit=limit)
to_retry = retries > 0 and self._is_server_side_invalid_response(videos, html) to_retry = retries > 0 and self._is_server_side_invalid_response(videos, html)
if to_retry: if to_retry:
retries -= 1
logger.debug( logger.debug(
"Retrying since YouTube returned invalid response for search " "Retrying since YouTube returned invalid response for search "
"results. Retries left: {retries}.".format(retries=retries) "results. Retries left: {retries}.".format(retries=retries)
) )
return self.search(query, limit=limit, retries=retries) return self.search(query, limit=limit, retries=retries-1)
return YouTubeVideos(videos) return YouTubeVideos(videos)

View File

@@ -163,7 +163,7 @@ class MetadataSearch:
if video is None: if video is None:
raise NoYouTubeVideoMatchError( raise NoYouTubeVideoMatchError(
'No matching videos found on YouTube for the search query "{}".'.format( 'No matching videos found on YouTube for the search query "{}".'.format(
search_query query
) )
) )
return video return video

View File

@@ -1,2 +1,2 @@
__version__ = "2.0.1" __version__ = "2.0.3"