fix: #275
This commit is contained in:
@@ -24,7 +24,7 @@ from routes.utils.watch.manager import check_watched_artists, get_watch_config
|
|||||||
from routes.utils.get_info import get_spotify_info
|
from routes.utils.get_info import get_spotify_info
|
||||||
|
|
||||||
# Import authentication dependencies
|
# Import authentication dependencies
|
||||||
from routes.auth.middleware import require_auth_from_state, require_admin_from_state, User
|
from routes.auth.middleware import require_auth_from_state, User
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@@ -43,7 +43,11 @@ def log_json(message_dict):
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/download/{artist_id}")
|
@router.get("/download/{artist_id}")
|
||||||
async def handle_artist_download(artist_id: str, request: Request, current_user: User = Depends(require_auth_from_state)):
|
async def handle_artist_download(
|
||||||
|
artist_id: str,
|
||||||
|
request: Request,
|
||||||
|
current_user: User = Depends(require_auth_from_state),
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Enqueues album download tasks for the given artist.
|
Enqueues album download tasks for the given artist.
|
||||||
Expected query parameters:
|
Expected query parameters:
|
||||||
@@ -58,8 +62,7 @@ async def handle_artist_download(artist_id: str, request: Request, current_user:
|
|||||||
# Validate required parameters
|
# Validate required parameters
|
||||||
if not url: # This check is mostly for safety, as url is constructed
|
if not url: # This check is mostly for safety, as url is constructed
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={"error": "Missing required parameter: url"},
|
content={"error": "Missing required parameter: url"}, status_code=400
|
||||||
status_code=400
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -68,7 +71,10 @@ async def handle_artist_download(artist_id: str, request: Request, current_user:
|
|||||||
|
|
||||||
# Delegate to the download_artist_albums function which will handle album filtering
|
# Delegate to the download_artist_albums function which will handle album filtering
|
||||||
successfully_queued_albums, duplicate_albums = download_artist_albums(
|
successfully_queued_albums, duplicate_albums = download_artist_albums(
|
||||||
url=url, album_type=album_type, request_args=dict(request.query_params)
|
url=url,
|
||||||
|
album_type=album_type,
|
||||||
|
request_args=dict(request.query_params),
|
||||||
|
username=current_user.username,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Return the list of album task IDs.
|
# Return the list of album task IDs.
|
||||||
@@ -85,7 +91,7 @@ async def handle_artist_download(artist_id: str, request: Request, current_user:
|
|||||||
|
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content=response_data,
|
content=response_data,
|
||||||
status_code=202 # Still 202 Accepted as some operations may have succeeded
|
status_code=202, # Still 202 Accepted as some operations may have succeeded
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
@@ -94,7 +100,7 @@ async def handle_artist_download(artist_id: str, request: Request, current_user:
|
|||||||
"message": str(e),
|
"message": str(e),
|
||||||
"traceback": traceback.format_exc(),
|
"traceback": traceback.format_exc(),
|
||||||
},
|
},
|
||||||
status_code=500
|
status_code=500,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -106,12 +112,14 @@ async def cancel_artist_download():
|
|||||||
"""
|
"""
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={"error": "Artist download cancellation is not supported."},
|
content={"error": "Artist download cancellation is not supported."},
|
||||||
status_code=400
|
status_code=400,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/info")
|
@router.get("/info")
|
||||||
async def get_artist_info(request: Request, current_user: User = Depends(require_auth_from_state)):
|
async def get_artist_info(
|
||||||
|
request: Request, current_user: User = Depends(require_auth_from_state)
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Retrieves Spotify artist metadata given a Spotify artist ID.
|
Retrieves Spotify artist metadata given a Spotify artist ID.
|
||||||
Expects a query parameter 'id' with the Spotify artist ID.
|
Expects a query parameter 'id' with the Spotify artist ID.
|
||||||
@@ -119,27 +127,25 @@ async def get_artist_info(request: Request, current_user: User = Depends(require
|
|||||||
spotify_id = request.query_params.get("id")
|
spotify_id = request.query_params.get("id")
|
||||||
|
|
||||||
if not spotify_id:
|
if not spotify_id:
|
||||||
return JSONResponse(
|
return JSONResponse(content={"error": "Missing parameter: id"}, status_code=400)
|
||||||
content={"error": "Missing parameter: id"},
|
|
||||||
status_code=400
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get artist metadata first
|
# Get artist metadata first
|
||||||
artist_metadata = get_spotify_info(spotify_id, "artist")
|
artist_metadata = get_spotify_info(spotify_id, "artist")
|
||||||
|
|
||||||
# Get artist discography for albums
|
# Get artist discography for albums
|
||||||
artist_discography = get_spotify_info(spotify_id, "artist_discography")
|
artist_discography = get_spotify_info(spotify_id, "artist_discography")
|
||||||
|
|
||||||
# Combine metadata with discography
|
# Combine metadata with discography
|
||||||
artist_info = {
|
artist_info = {**artist_metadata, "albums": artist_discography}
|
||||||
**artist_metadata,
|
|
||||||
"albums": artist_discography
|
|
||||||
}
|
|
||||||
|
|
||||||
# If artist_info is successfully fetched and has albums,
|
# If artist_info is successfully fetched and has albums,
|
||||||
# check if the artist is watched and augment album items with is_locally_known status
|
# check if the artist is watched and augment album items with is_locally_known status
|
||||||
if artist_info and artist_info.get("albums") and artist_info["albums"].get("items"):
|
if (
|
||||||
|
artist_info
|
||||||
|
and artist_info.get("albums")
|
||||||
|
and artist_info["albums"].get("items")
|
||||||
|
):
|
||||||
watched_artist_details = get_watched_artist(
|
watched_artist_details = get_watched_artist(
|
||||||
spotify_id
|
spotify_id
|
||||||
) # spotify_id is the artist ID
|
) # spotify_id is the artist ID
|
||||||
@@ -155,13 +161,11 @@ async def get_artist_info(request: Request, current_user: User = Depends(require
|
|||||||
# If not watched, or no albums, is_locally_known will not be added.
|
# If not watched, or no albums, is_locally_known will not be added.
|
||||||
# Frontend should handle absence of this key as false.
|
# Frontend should handle absence of this key as false.
|
||||||
|
|
||||||
return JSONResponse(
|
return JSONResponse(content=artist_info, status_code=200)
|
||||||
content=artist_info, status_code=200
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content={"error": str(e), "traceback": traceback.format_exc()},
|
content={"error": str(e), "traceback": traceback.format_exc()},
|
||||||
status_code=500
|
status_code=500,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -169,11 +173,16 @@ async def get_artist_info(request: Request, current_user: User = Depends(require
|
|||||||
|
|
||||||
|
|
||||||
@router.put("/watch/{artist_spotify_id}")
|
@router.put("/watch/{artist_spotify_id}")
|
||||||
async def add_artist_to_watchlist(artist_spotify_id: str, current_user: User = Depends(require_auth_from_state)):
|
async def add_artist_to_watchlist(
|
||||||
|
artist_spotify_id: str, current_user: User = Depends(require_auth_from_state)
|
||||||
|
):
|
||||||
"""Adds an artist to the watchlist."""
|
"""Adds an artist to the watchlist."""
|
||||||
watch_config = get_watch_config()
|
watch_config = get_watch_config()
|
||||||
if not watch_config.get("enabled", False):
|
if not watch_config.get("enabled", False):
|
||||||
raise HTTPException(status_code=403, detail={"error": "Watch feature is currently disabled globally."})
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail={"error": "Watch feature is currently disabled globally."},
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(f"Attempting to add artist {artist_spotify_id} to watchlist.")
|
logger.info(f"Attempting to add artist {artist_spotify_id} to watchlist.")
|
||||||
try:
|
try:
|
||||||
@@ -182,7 +191,7 @@ async def add_artist_to_watchlist(artist_spotify_id: str, current_user: User = D
|
|||||||
|
|
||||||
# Get artist metadata directly for name and basic info
|
# Get artist metadata directly for name and basic info
|
||||||
artist_metadata = get_spotify_info(artist_spotify_id, "artist")
|
artist_metadata = get_spotify_info(artist_spotify_id, "artist")
|
||||||
|
|
||||||
# Get artist discography for album count
|
# Get artist discography for album count
|
||||||
artist_album_list_data = get_spotify_info(
|
artist_album_list_data = get_spotify_info(
|
||||||
artist_spotify_id, "artist_discography"
|
artist_spotify_id, "artist_discography"
|
||||||
@@ -197,7 +206,7 @@ async def add_artist_to_watchlist(artist_spotify_id: str, current_user: User = D
|
|||||||
status_code=404,
|
status_code=404,
|
||||||
detail={
|
detail={
|
||||||
"error": f"Could not fetch artist metadata for {artist_spotify_id} to initiate watch."
|
"error": f"Could not fetch artist metadata for {artist_spotify_id} to initiate watch."
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if we got album data
|
# Check if we got album data
|
||||||
@@ -213,7 +222,9 @@ async def add_artist_to_watchlist(artist_spotify_id: str, current_user: User = D
|
|||||||
"id": artist_spotify_id,
|
"id": artist_spotify_id,
|
||||||
"name": artist_metadata.get("name", "Unknown Artist"),
|
"name": artist_metadata.get("name", "Unknown Artist"),
|
||||||
"albums": { # Mimic structure if add_artist_db expects it for total_albums
|
"albums": { # Mimic structure if add_artist_db expects it for total_albums
|
||||||
"total": artist_album_list_data.get("total", 0) if artist_album_list_data else 0
|
"total": artist_album_list_data.get("total", 0)
|
||||||
|
if artist_album_list_data
|
||||||
|
else 0
|
||||||
},
|
},
|
||||||
# Add any other fields add_artist_db might expect from a true artist object if necessary
|
# Add any other fields add_artist_db might expect from a true artist object if necessary
|
||||||
}
|
}
|
||||||
@@ -232,11 +243,16 @@ async def add_artist_to_watchlist(artist_spotify_id: str, current_user: User = D
|
|||||||
logger.error(
|
logger.error(
|
||||||
f"Error adding artist {artist_spotify_id} to watchlist: {e}", exc_info=True
|
f"Error adding artist {artist_spotify_id} to watchlist: {e}", exc_info=True
|
||||||
)
|
)
|
||||||
raise HTTPException(status_code=500, detail={"error": f"Could not add artist to watchlist: {str(e)}"})
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail={"error": f"Could not add artist to watchlist: {str(e)}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/watch/{artist_spotify_id}/status")
|
@router.get("/watch/{artist_spotify_id}/status")
|
||||||
async def get_artist_watch_status(artist_spotify_id: str, current_user: User = Depends(require_auth_from_state)):
|
async def get_artist_watch_status(
|
||||||
|
artist_spotify_id: str, current_user: User = Depends(require_auth_from_state)
|
||||||
|
):
|
||||||
"""Checks if a specific artist is being watched."""
|
"""Checks if a specific artist is being watched."""
|
||||||
logger.info(f"Checking watch status for artist {artist_spotify_id}.")
|
logger.info(f"Checking watch status for artist {artist_spotify_id}.")
|
||||||
try:
|
try:
|
||||||
@@ -250,22 +266,29 @@ async def get_artist_watch_status(artist_spotify_id: str, current_user: User = D
|
|||||||
f"Error checking watch status for artist {artist_spotify_id}: {e}",
|
f"Error checking watch status for artist {artist_spotify_id}: {e}",
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
raise HTTPException(status_code=500, detail={"error": f"Could not check watch status: {str(e)}"})
|
raise HTTPException(
|
||||||
|
status_code=500, detail={"error": f"Could not check watch status: {str(e)}"}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/watch/{artist_spotify_id}")
|
@router.delete("/watch/{artist_spotify_id}")
|
||||||
async def remove_artist_from_watchlist(artist_spotify_id: str, current_user: User = Depends(require_auth_from_state)):
|
async def remove_artist_from_watchlist(
|
||||||
|
artist_spotify_id: str, current_user: User = Depends(require_auth_from_state)
|
||||||
|
):
|
||||||
"""Removes an artist from the watchlist."""
|
"""Removes an artist from the watchlist."""
|
||||||
watch_config = get_watch_config()
|
watch_config = get_watch_config()
|
||||||
if not watch_config.get("enabled", False):
|
if not watch_config.get("enabled", False):
|
||||||
raise HTTPException(status_code=403, detail={"error": "Watch feature is currently disabled globally."})
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail={"error": "Watch feature is currently disabled globally."},
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(f"Attempting to remove artist {artist_spotify_id} from watchlist.")
|
logger.info(f"Attempting to remove artist {artist_spotify_id} from watchlist.")
|
||||||
try:
|
try:
|
||||||
if not get_watched_artist(artist_spotify_id):
|
if not get_watched_artist(artist_spotify_id):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=404,
|
status_code=404,
|
||||||
detail={"error": f"Artist {artist_spotify_id} not found in watchlist."}
|
detail={"error": f"Artist {artist_spotify_id} not found in watchlist."},
|
||||||
)
|
)
|
||||||
|
|
||||||
remove_artist_db(artist_spotify_id)
|
remove_artist_db(artist_spotify_id)
|
||||||
@@ -280,23 +303,30 @@ async def remove_artist_from_watchlist(artist_spotify_id: str, current_user: Use
|
|||||||
)
|
)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500,
|
status_code=500,
|
||||||
detail={"error": f"Could not remove artist from watchlist: {str(e)}"}
|
detail={"error": f"Could not remove artist from watchlist: {str(e)}"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/watch/list")
|
@router.get("/watch/list")
|
||||||
async def list_watched_artists_endpoint(current_user: User = Depends(require_auth_from_state)):
|
async def list_watched_artists_endpoint(
|
||||||
|
current_user: User = Depends(require_auth_from_state),
|
||||||
|
):
|
||||||
"""Lists all artists currently in the watchlist."""
|
"""Lists all artists currently in the watchlist."""
|
||||||
try:
|
try:
|
||||||
artists = get_watched_artists()
|
artists = get_watched_artists()
|
||||||
return [dict(artist) for artist in artists]
|
return [dict(artist) for artist in artists]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error listing watched artists: {e}", exc_info=True)
|
logger.error(f"Error listing watched artists: {e}", exc_info=True)
|
||||||
raise HTTPException(status_code=500, detail={"error": f"Could not list watched artists: {str(e)}"})
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail={"error": f"Could not list watched artists: {str(e)}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/watch/trigger_check")
|
@router.post("/watch/trigger_check")
|
||||||
async def trigger_artist_check_endpoint(current_user: User = Depends(require_auth_from_state)):
|
async def trigger_artist_check_endpoint(
|
||||||
|
current_user: User = Depends(require_auth_from_state),
|
||||||
|
):
|
||||||
"""Manually triggers the artist checking mechanism for all watched artists."""
|
"""Manually triggers the artist checking mechanism for all watched artists."""
|
||||||
watch_config = get_watch_config()
|
watch_config = get_watch_config()
|
||||||
if not watch_config.get("enabled", False):
|
if not watch_config.get("enabled", False):
|
||||||
@@ -304,7 +334,7 @@ async def trigger_artist_check_endpoint(current_user: User = Depends(require_aut
|
|||||||
status_code=403,
|
status_code=403,
|
||||||
detail={
|
detail={
|
||||||
"error": "Watch feature is currently disabled globally. Cannot trigger check."
|
"error": "Watch feature is currently disabled globally. Cannot trigger check."
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info("Manual trigger for artist check received for all artists.")
|
logger.info("Manual trigger for artist check received for all artists.")
|
||||||
@@ -320,12 +350,14 @@ async def trigger_artist_check_endpoint(current_user: User = Depends(require_aut
|
|||||||
)
|
)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500,
|
status_code=500,
|
||||||
detail={"error": f"Could not trigger artist check for all: {str(e)}"}
|
detail={"error": f"Could not trigger artist check for all: {str(e)}"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/watch/trigger_check/{artist_spotify_id}")
|
@router.post("/watch/trigger_check/{artist_spotify_id}")
|
||||||
async def trigger_specific_artist_check_endpoint(artist_spotify_id: str, current_user: User = Depends(require_auth_from_state)):
|
async def trigger_specific_artist_check_endpoint(
|
||||||
|
artist_spotify_id: str, current_user: User = Depends(require_auth_from_state)
|
||||||
|
):
|
||||||
"""Manually triggers the artist checking mechanism for a specific artist."""
|
"""Manually triggers the artist checking mechanism for a specific artist."""
|
||||||
watch_config = get_watch_config()
|
watch_config = get_watch_config()
|
||||||
if not watch_config.get("enabled", False):
|
if not watch_config.get("enabled", False):
|
||||||
@@ -333,7 +365,7 @@ async def trigger_specific_artist_check_endpoint(artist_spotify_id: str, current
|
|||||||
status_code=403,
|
status_code=403,
|
||||||
detail={
|
detail={
|
||||||
"error": "Watch feature is currently disabled globally. Cannot trigger check."
|
"error": "Watch feature is currently disabled globally. Cannot trigger check."
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -349,7 +381,7 @@ async def trigger_specific_artist_check_endpoint(artist_spotify_id: str, current
|
|||||||
status_code=404,
|
status_code=404,
|
||||||
detail={
|
detail={
|
||||||
"error": f"Artist {artist_spotify_id} is not in the watchlist. Add it first."
|
"error": f"Artist {artist_spotify_id} is not in the watchlist. Add it first."
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
thread = threading.Thread(
|
thread = threading.Thread(
|
||||||
@@ -373,12 +405,16 @@ async def trigger_specific_artist_check_endpoint(artist_spotify_id: str, current
|
|||||||
status_code=500,
|
status_code=500,
|
||||||
detail={
|
detail={
|
||||||
"error": f"Could not trigger artist check for {artist_spotify_id}: {str(e)}"
|
"error": f"Could not trigger artist check for {artist_spotify_id}: {str(e)}"
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/watch/{artist_spotify_id}/albums")
|
@router.post("/watch/{artist_spotify_id}/albums")
|
||||||
async def mark_albums_as_known_for_artist(artist_spotify_id: str, request: Request, current_user: User = Depends(require_auth_from_state)):
|
async def mark_albums_as_known_for_artist(
|
||||||
|
artist_spotify_id: str,
|
||||||
|
request: Request,
|
||||||
|
current_user: User = Depends(require_auth_from_state),
|
||||||
|
):
|
||||||
"""Fetches details for given album IDs and adds/updates them in the artist's local DB table."""
|
"""Fetches details for given album IDs and adds/updates them in the artist's local DB table."""
|
||||||
watch_config = get_watch_config()
|
watch_config = get_watch_config()
|
||||||
if not watch_config.get("enabled", False):
|
if not watch_config.get("enabled", False):
|
||||||
@@ -386,7 +422,7 @@ async def mark_albums_as_known_for_artist(artist_spotify_id: str, request: Reque
|
|||||||
status_code=403,
|
status_code=403,
|
||||||
detail={
|
detail={
|
||||||
"error": "Watch feature is currently disabled globally. Cannot mark albums."
|
"error": "Watch feature is currently disabled globally. Cannot mark albums."
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(f"Attempting to mark albums as known for artist {artist_spotify_id}.")
|
logger.info(f"Attempting to mark albums as known for artist {artist_spotify_id}.")
|
||||||
@@ -399,13 +435,13 @@ async def mark_albums_as_known_for_artist(artist_spotify_id: str, request: Reque
|
|||||||
status_code=400,
|
status_code=400,
|
||||||
detail={
|
detail={
|
||||||
"error": "Invalid request body. Expecting a JSON array of album Spotify IDs."
|
"error": "Invalid request body. Expecting a JSON array of album Spotify IDs."
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if not get_watched_artist(artist_spotify_id):
|
if not get_watched_artist(artist_spotify_id):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=404,
|
status_code=404,
|
||||||
detail={"error": f"Artist {artist_spotify_id} is not being watched."}
|
detail={"error": f"Artist {artist_spotify_id} is not being watched."},
|
||||||
)
|
)
|
||||||
|
|
||||||
fetched_albums_details = []
|
fetched_albums_details = []
|
||||||
@@ -446,11 +482,18 @@ async def mark_albums_as_known_for_artist(artist_spotify_id: str, request: Reque
|
|||||||
f"Error marking albums as known for artist {artist_spotify_id}: {e}",
|
f"Error marking albums as known for artist {artist_spotify_id}: {e}",
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
raise HTTPException(status_code=500, detail={"error": f"Could not mark albums as known: {str(e)}"})
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail={"error": f"Could not mark albums as known: {str(e)}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/watch/{artist_spotify_id}/albums")
|
@router.delete("/watch/{artist_spotify_id}/albums")
|
||||||
async def mark_albums_as_missing_locally_for_artist(artist_spotify_id: str, request: Request, current_user: User = Depends(require_auth_from_state)):
|
async def mark_albums_as_missing_locally_for_artist(
|
||||||
|
artist_spotify_id: str,
|
||||||
|
request: Request,
|
||||||
|
current_user: User = Depends(require_auth_from_state),
|
||||||
|
):
|
||||||
"""Removes specified albums from the artist's local DB table."""
|
"""Removes specified albums from the artist's local DB table."""
|
||||||
watch_config = get_watch_config()
|
watch_config = get_watch_config()
|
||||||
if not watch_config.get("enabled", False):
|
if not watch_config.get("enabled", False):
|
||||||
@@ -458,7 +501,7 @@ async def mark_albums_as_missing_locally_for_artist(artist_spotify_id: str, requ
|
|||||||
status_code=403,
|
status_code=403,
|
||||||
detail={
|
detail={
|
||||||
"error": "Watch feature is currently disabled globally. Cannot mark albums."
|
"error": "Watch feature is currently disabled globally. Cannot mark albums."
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -473,13 +516,13 @@ async def mark_albums_as_missing_locally_for_artist(artist_spotify_id: str, requ
|
|||||||
status_code=400,
|
status_code=400,
|
||||||
detail={
|
detail={
|
||||||
"error": "Invalid request body. Expecting a JSON array of album Spotify IDs."
|
"error": "Invalid request body. Expecting a JSON array of album Spotify IDs."
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if not get_watched_artist(artist_spotify_id):
|
if not get_watched_artist(artist_spotify_id):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=404,
|
status_code=404,
|
||||||
detail={"error": f"Artist {artist_spotify_id} is not being watched."}
|
detail={"error": f"Artist {artist_spotify_id} is not being watched."},
|
||||||
)
|
)
|
||||||
|
|
||||||
deleted_count = remove_specific_albums_from_artist_table(
|
deleted_count = remove_specific_albums_from_artist_table(
|
||||||
@@ -498,4 +541,7 @@ async def mark_albums_as_missing_locally_for_artist(artist_spotify_id: str, requ
|
|||||||
f"Error marking albums as missing (deleting locally) for artist {artist_spotify_id}: {e}",
|
f"Error marking albums as missing (deleting locally) for artist {artist_spotify_id}: {e}",
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
raise HTTPException(status_code=500, detail={"error": f"Could not mark albums as missing: {str(e)}"})
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail={"error": f"Could not mark albums as missing: {str(e)}"},
|
||||||
|
)
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ def get_artist_discography(
|
|||||||
|
|
||||||
|
|
||||||
def download_artist_albums(
|
def download_artist_albums(
|
||||||
url, album_type="album,single,compilation", request_args=None
|
url, album_type="album,single,compilation", request_args=None, username=None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Download albums by an artist, filtered by album types.
|
Download albums by an artist, filtered by album types.
|
||||||
@@ -97,6 +97,7 @@ def download_artist_albums(
|
|||||||
album_type (str): Comma-separated list of album types to download
|
album_type (str): Comma-separated list of album types to download
|
||||||
(album, single, compilation, appears_on)
|
(album, single, compilation, appears_on)
|
||||||
request_args (dict): Original request arguments for tracking
|
request_args (dict): Original request arguments for tracking
|
||||||
|
username (str | None): Username initiating the request, used for per-user separation
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (list of successfully queued albums, list of duplicate albums)
|
tuple: (list of successfully queued albums, list of duplicate albums)
|
||||||
@@ -160,11 +161,15 @@ def download_artist_albums(
|
|||||||
album_name = album.get("name", "Unknown Album")
|
album_name = album.get("name", "Unknown Album")
|
||||||
album_artists = album.get("artists", [])
|
album_artists = album.get("artists", [])
|
||||||
album_artist = (
|
album_artist = (
|
||||||
album_artists[0].get("name", "Unknown Artist") if album_artists else "Unknown Artist"
|
album_artists[0].get("name", "Unknown Artist")
|
||||||
|
if album_artists
|
||||||
|
else "Unknown Artist"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not album_url:
|
if not album_url:
|
||||||
logger.warning(f"Skipping album '{album_name}' because it has no Spotify URL.")
|
logger.warning(
|
||||||
|
f"Skipping album '{album_name}' because it has no Spotify URL."
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
task_data = {
|
task_data = {
|
||||||
@@ -174,6 +179,8 @@ def download_artist_albums(
|
|||||||
"artist": album_artist,
|
"artist": album_artist,
|
||||||
"orig_request": request_args,
|
"orig_request": request_args,
|
||||||
}
|
}
|
||||||
|
if username:
|
||||||
|
task_data["username"] = username
|
||||||
|
|
||||||
try:
|
try:
|
||||||
task_id = download_queue_manager.add_task(task_data)
|
task_id = download_queue_manager.add_task(task_data)
|
||||||
@@ -199,7 +206,9 @@ def download_artist_albums(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to queue album {album_name} for an unknown reason: {e}")
|
logger.error(
|
||||||
|
f"Failed to queue album {album_name} for an unknown reason: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Artist album processing: {len(successfully_queued_albums)} queued, {len(duplicate_albums)} duplicates found."
|
f"Artist album processing: {len(successfully_queued_albums)} queued, {len(duplicate_albums)} duplicates found."
|
||||||
|
|||||||
Reference in New Issue
Block a user