songs2slides

A tool that automatically finds song lyrics and creates lyric slideshows
git clone https://git.ashermorgan.net/songs2slides/
Log | Files | Refs | README

commit c9f1da022013341c980f1c72698622fa432ace53
parent 8ea129818792f985f643b7291f6ab1fd2427eea4
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Fri, 15 Nov 2024 19:17:35 -0800

Specify if song wasn't found or API error occurred

Diffstat:
Msongs2slides/core.py | 16+++++++++++++---
Msongs2slides/routes.py | 9+++++++--
Msongs2slides/templates/create-step-2.html | 1+
Mtests/test_routes.py | 7++++---
4 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/songs2slides/core.py b/songs2slides/core.py @@ -26,6 +26,10 @@ class SongData: artist: str lyrics: str +class SongNotFound(Exception): + """Raised when the API cannot find the lyrics to a song""" + pass + def filter_lyrics(lyrics: str): """ Filter raw lyrics to remove text enclosed in brackets or parenthesis @@ -75,7 +79,7 @@ def get_song_data(title: str, artist:str): # Get API URL url = os.getenv('API_URL') if url is None: - raise Exception() + raise Exception('Bad API_URL') url = url.replace('{title}', title, 1) url = url.replace('{artist}', artist, 1) @@ -84,14 +88,20 @@ def get_song_data(title: str, artist:str): headers = { 'Authorization': auth } if auth else {} # Query API - data = requests.get(url, headers=headers).json() + res = requests.get(url, headers=headers) + if res.status_code != requests.codes.ok: + if res.status_code == 404: + raise SongNotFound() + else: + res.raise_for_status() + data = res.json() # Parse response if 'lyrics' in data.keys(): return SongData(data['title'], data['artist'], filter_lyrics(data['lyrics'])) else: - raise Exception() + raise Exception('API returned invalid lyric data') def parse_song_lyrics(lyrics: str, lines_per_slide: int): """ diff --git a/songs2slides/routes.py b/songs2slides/routes.py @@ -59,19 +59,24 @@ def create_step_2(): songs = parse_form(request.form) # Get lyrics + api_error = True # Whether an API error occured for all requests for i in range(len(songs)): try: songs[i] = core.get_song_data(songs[i].title, songs[i].artist) + api_error = False slides = core.parse_song_lyrics(songs[i].lyrics, 4) songs[i].lyrics = '\n\n'.join(slides) - except: + except core.SongNotFound: + api_error = False + except Exception as e: pass # Count missing songs missing = sum([1 for x in songs if x.lyrics == None]) # Return song data - return render_template('create-step-2.html', songs=songs, missing=missing) + return render_template('create-step-2.html', songs=songs, missing=missing, + api_error=api_error) @bp.get('/create/step-3/') def create_step_3_get(): diff --git a/songs2slides/templates/create-step-2.html b/songs2slides/templates/create-step-2.html @@ -20,6 +20,7 @@ </p> <p id="missing-message" {% if missing == 0 %} hidden {% endif %}> + {% if api_error %} Our lyric API is currently down. {% endif %} Lyrics must be entered manually for <span id="missing-count">{{ missing }}</span> song(s). </p> diff --git a/tests/test_routes.py b/tests/test_routes.py @@ -34,8 +34,8 @@ def test_get_lyrics_basic(client, mocker): core.parse_song_lyrics.assert_has_calls([ mocker.call('L1', 4), mocker.call('L2', 4) ]) - routes.render_template.assert_called_with('create-step-2.html', - songs=songs, missing=0) + routes.render_template.assert_called_with('create-step-2.html', songs=songs, + missing=0, api_error=False) def test_get_lyrics_one_error(client, mocker): # Mock get_song_data, parse_song_lyrics, and render_template @@ -62,7 +62,8 @@ def test_get_lyrics_one_error(client, mocker): mocker.call('T1', 'A1'), mocker.call('T2', 'A2') ]) core.parse_song_lyrics.assert_has_calls([mocker.call('L2', 4)]) - routes.render_template.assert_called_with('create-step-2.html', songs=songs, missing=1) + routes.render_template.assert_called_with('create-step-2.html', songs=songs, + missing=1, api_error=False) def test_get_lyrics_missing_artist(client, mocker): # Mock get_song_data