Better Errorhandling in case of spotify api errors

Addresses issue #20
This commit is contained in:
Kamil
2024-11-27 17:20:47 +00:00
parent c6eb95112e
commit b60a882dab
6 changed files with 109 additions and 59 deletions

View File

@@ -5,6 +5,8 @@ from functools import wraps
from celery.result import AsyncResult from celery.result import AsyncResult
from app.tasks import download_missing_tracks,check_for_playlist_updates, update_all_playlists_track_status, update_jellyfin_id_for_downloaded_tracks from app.tasks import download_missing_tracks,check_for_playlist_updates, update_all_playlists_track_status, update_jellyfin_id_for_downloaded_tracks
from jellyfin.objects import PlaylistMetadata from jellyfin.objects import PlaylistMetadata
from spotipy.exceptions import SpotifyException
import re import re
TASK_STATUS = { TASK_STATUS = {
@@ -129,12 +131,9 @@ def get_cached_spotify_playlist(playlist_id):
:param playlist_id: The Spotify playlist ID. :param playlist_id: The Spotify playlist ID.
:return: Playlist data as a dictionary, or None if an error occurs. :return: Playlist data as a dictionary, or None if an error occurs.
""" """
try: playlist_data = sp.playlist(playlist_id) # Fetch data from Spotify API
playlist_data = sp.playlist(playlist_id) # Fetch data from Spotify API return playlist_data
return playlist_data
except Exception as e:
app.logger.error(f"Error fetching playlist {playlist_id} from Spotify: {str(e)}")
return None
@cache.memoize(timeout=3600*24*10) @cache.memoize(timeout=3600*24*10)
def get_cached_spotify_track(track_id): def get_cached_spotify_track(track_id):
""" """
@@ -180,15 +179,21 @@ def prepArtistData(data):
def getFeaturedPlaylists(country,offset): def getFeaturedPlaylists(country: str, offset: int):
playlists_data = sp.featured_playlists(country=country, limit=16, offset=offset) try:
playlists_data = sp.featured_playlists(country=country, limit=16, offset=offset)
return prepPlaylistData(playlists_data), playlists_data['playlists']['total'],'Featured Playlists' return prepPlaylistData(playlists_data), playlists_data['playlists']['total'], 'Featured Playlists'
except SpotifyException as e:
app.logger.error(f"Spotify API error in getFeaturedPlaylists: {e}")
return [], e, f'Error: Could not load featured playlists. Please try again later. This is most likely due to an Error in the Spotify API or an rate limit has been reached.'
def getCategoryPlaylists(category,offset): def getCategoryPlaylists(category: str, offset: int):
playlists_data = sp.category_playlists(category_id=category, limit=16, offset=offset) try:
playlists_data = sp.category_playlists(category_id=category, limit=16, offset=offset)
return prepPlaylistData(playlists_data), playlists_data['playlists']['total'],f"Category {playlists_data['message']}" return prepPlaylistData(playlists_data), playlists_data['playlists']['total'], f"Category {playlists_data['message']}"
except SpotifyException as e:
app.logger.error(f"Spotify API error in getCategoryPlaylists: {e}")
return [], e, 'Error: Could not load category playlists. Please try again later. This is most likely due to an Error in the Spotify API or an rate limit has been reached.'
def getCategories(country,offset): def getCategories(country,offset):
categories_data = sp.categories(limit=16, offset= offset) categories_data = sp.categories(limit=16, offset= offset)

View File

@@ -3,7 +3,7 @@ from flask import Flask, jsonify, render_template, request, redirect, url_for, s
from sqlalchemy import insert from sqlalchemy import insert
from app import app, db, jellyfin, functions, device_id,sp from app import app, db, jellyfin, functions, device_id,sp
from app.models import Playlist,Track, playlist_tracks from app.models import Playlist,Track, playlist_tracks
from spotipy.exceptions import SpotifyException
from jellyfin.objects import PlaylistMetadata from jellyfin.objects import PlaylistMetadata
@@ -38,11 +38,15 @@ def jellyfin_playlists():
prepared_data = functions.prepPlaylistData(spotify_data) prepared_data = functions.prepPlaylistData(spotify_data)
return render_template('jellyfin_playlists.html', playlists=prepared_data) return render_template('jellyfin_playlists.html', playlists=prepared_data)
except SpotifyException as e:
app.logger.error(f"Error fetching monitored playlists: {e}")
error_data, error_message = e, f'Could not retrieve monitored Playlists. Please try again later. This is most likely due to an Error in the Spotify API or an rate limit has been reached.'
return render_template('jellyfin_playlists.html', playlists=functions.prepPlaylistData({'playlists': {'items': []}}), error_message=error_message,error_data = error_data)
except Exception as e: except Exception as e:
app.logger.error(f"Error in /jellyfin_playlists route: {str(e)}") app.logger.error(f"Error in /jellyfin_playlists route: {str(e)}")
flash('An error occurred while fetching playlists.', 'danger') flash('An error occurred while fetching playlists.', 'danger')
return render_template('jellyfin_playlists.html', playlists=functions.prepPlaylistData({'playlists': {'items': []}})) return render_template('jellyfin_playlists.html', playlists=functions.prepPlaylistData({'playlists': {'items': []}}), error_message='An error occurred while fetching playlists.',error_data = e)
@app.route('/addplaylist', methods=['POST']) @app.route('/addplaylist', methods=['POST'])

View File

@@ -3,6 +3,7 @@ from app import app, db, functions, sp, jellyfin, celery, jellyfin_admin_token,
from app.models import JellyfinUser,Playlist,Track from app.models import JellyfinUser,Playlist,Track
from celery.result import AsyncResult from celery.result import AsyncResult
from .version import __version__ from .version import __version__
from spotipy.exceptions import SpotifyException
@app.context_processor @app.context_processor
def add_context(): def add_context():
@@ -140,32 +141,46 @@ def loaditems():
limit = 20 # Define a limit for pagination limit = 20 # Define a limit for pagination
additional_query = '' additional_query = ''
items_subtitle = '' items_subtitle = ''
error_message = None # Placeholder for error messages
error_data = ''
if request.path == '/playlists/monitored': if request.path == '/playlists/monitored':
# Step 1: Query the database for monitored playlists try:
db_playlists = db.session.query(Playlist).offset(offset).limit(limit).all() db_playlists = db.session.query(Playlist).offset(offset).limit(limit).all()
max_items = db.session.query(Playlist).count() max_items = db.session.query(Playlist).count()
spotify_playlist_ids = [playlist.spotify_playlist_id for playlist in db_playlists]
# Collect Spotify Playlist IDs from the database spotify_data = functions.get_cached_spotify_playlists(tuple(spotify_playlist_ids))
spotify_playlist_ids = [playlist.spotify_playlist_id for playlist in db_playlists] data = functions.prepPlaylistData(spotify_data)
items_title = "Monitored Playlists"
spotify_data = functions.get_cached_spotify_playlists(tuple(spotify_playlist_ids)) items_subtitle = "These playlists are already monitored by the Server. If you add one to your Jellyfin account, they will be available immediately."
except SpotifyException as e:
# Step 3: Pass the Spotify data to prepPlaylistData for processing app.logger.error(f"Error fetching monitored playlists: {e}")
data = functions.prepPlaylistData(spotify_data) data, max_items, items_title = [], e, f'Could not retrieve monitored Playlists. Please try again later. This is most likely due to an Error in the Spotify API or an rate limit has been reached.'
items_title = "Monitored Playlists" error_message = items_title
items_subtitle = "This playlists are already monitored by the Server, if you add one of these to your Jellyfin account, they will be available immediately." error_data = max_items
elif request.path == '/playlists': elif request.path == '/playlists':
cat = request.args.get('cat', None) cat = request.args.get('cat', None)
if cat is not None: if cat is not None:
data, max_items, items_title = functions.getCategoryPlaylists(category=cat, offset=offset) data, max_items, items_title = functions.getCategoryPlaylists(category=cat, offset=offset)
if not data: # Check if data is empty
error_message = items_title # Set the error message from the function
error_data = max_items
additional_query += f"&cat={cat}" additional_query += f"&cat={cat}"
else: else:
data, max_items, items_title = functions.getFeaturedPlaylists(country=country, offset=offset) data, max_items, items_title = functions.getFeaturedPlaylists(country=country, offset=offset)
if not data: # Check if data is empty
error_message = items_title # Set the error message from the function
error_data = max_items
elif request.path == '/categories': elif request.path == '/categories':
data, max_items, items_title = functions.getCategories(country=country, offset=offset) try:
data, max_items, items_title = functions.getCategories(country=country, offset=offset)
except Exception as e:
app.logger.error(f"Error fetching categories: {e}")
data, max_items, items_title = [], e, f'Error: Could not load categories. Please try again later. '
error_message = items_title
error_data = max_items
next_offset = offset + len(data) next_offset = offset + len(data)
total_items = max_items total_items = max_items
@@ -175,8 +190,10 @@ def loaditems():
'total_items': total_items, 'total_items': total_items,
'endpoint': request.path, 'endpoint': request.path,
'items_title': items_title, 'items_title': items_title,
'items_subtitle' : items_subtitle, 'items_subtitle': items_subtitle,
'additional_query': additional_query 'additional_query': additional_query,
'error_message': error_message, # Pass error message to the template
'error_data': error_data, # Pass error message to the template
} }
if request.headers.get('HX-Request'): # Check if the request is from HTMX if request.headers.get('HX-Request'): # Check if the request is from HTMX

View File

@@ -127,31 +127,34 @@ def download_missing_tracks(self):
processed_tracks+=1 processed_tracks+=1
continue continue
# region search with fingerprinting # region search with fingerprinting
preview_url = spotify_track.get('preview_url') if spotify_track:
if not preview_url: preview_url = spotify_track.get('preview_url')
app.logger.error(f"Preview URL not found for track {track.name}.") if not preview_url:
# Decide whether to skip or proceed to download app.logger.error(f"Preview URL not found for track {track.name}.")
# For now, we'll proceed to download # Decide whether to skip or proceed to download
else: # For now, we'll proceed to download
# Get the list of Spotify artist names
spotify_artists = [artist['name'] for artist in spotify_track['artists']]
# Perform the search in Jellyfin
match_found, jellyfin_file_path = jellyfin.search_track_in_jellyfin(
session_token=jellyfin_admin_token,
preview_url=preview_url,
song_name=track.name,
artist_names=spotify_artists
)
if match_found:
app.logger.info(f"Match found in Jellyfin for track {track.name}. Skipping download.")
track.downloaded = True
track.filesystem_path = jellyfin_file_path
db.session.commit()
continue
else: else:
app.logger.info(f"No match found in Jellyfin for track {track.name}. Proceeding to download.") # Get the list of Spotify artist names
spotify_artists = [artist['name'] for artist in spotify_track['artists']]
# Perform the search in Jellyfin
match_found, jellyfin_file_path = jellyfin.search_track_in_jellyfin(
session_token=jellyfin_admin_token,
preview_url=preview_url,
song_name=track.name,
artist_names=spotify_artists
)
if match_found:
app.logger.info(f"Match found in Jellyfin for track {track.name}. Skipping download.")
track.downloaded = True
track.filesystem_path = jellyfin_file_path
db.session.commit()
continue
else:
app.logger.info(f"No match found in Jellyfin for track {track.name}. Proceeding to download.")
else:
app.logger.warning(f"spotify_track not set, see previous log messages")
#endregion #endregion
#endregion #endregion

View File

@@ -1,6 +1,16 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
{% if error_message %}
<div class="alert alert-danger mt-5" role="alert">
<h4 class="alert-heading">🚨Something went wrong🚨</h4>
<p>{{ error_message }}</p>
<hr>
<p>Additional Information:</p>
<p>{{error_data}}</p>
</div>
{% else %}
<h1 class="mb-4">{{ items_title }}</h1> <h1 class="mb-4">{{ items_title }}</h1>
<h6 class="mb-4">{{ items_subtitle }}</h6> <h6 class="mb-4">{{ items_subtitle }}</h6>
<div class="row row-cols-1 row-cols-md-4 row-cols-lg-6 g-4" id="items-container"> <div class="row row-cols-1 row-cols-md-4 row-cols-lg-6 g-4" id="items-container">
@@ -8,5 +18,6 @@
</div> </div>
{% endif %}
{% endblock %} {% endblock %}

View File

@@ -1,6 +1,16 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
{% if error_message %}
<div class="alert alert-danger mt-5" role="alert">
<h4 class="alert-heading">🚨Something went wrong🚨</h4>
<p>{{ error_message }}</p>
<hr>
<p>Additional Information:</p>
<p>{{error_data}}</p>
</div>
{% else %}
<h1 >Your subscribed Jellyfin Playlists</h1> <h1 >Your subscribed Jellyfin Playlists</h1>
<h6 ></h6> <h6 ></h6>
<div class="row row-cols-1 row-cols-md-4 row-cols-lg-6 g-4" id="items-container"> <div class="row row-cols-1 row-cols-md-4 row-cols-lg-6 g-4" id="items-container">
@@ -10,6 +20,6 @@
{% endfor %} {% endfor %}
</div> </div>
{%endif%}
{% endblock %} {% endblock %}