2025-06-25 13:53:24 +02:00
|
|
|
# lastfm_helpers.py
|
|
|
|
|
|
|
|
|
|
import pylast
|
2025-06-25 12:31:23 +00:00
|
|
|
#from config import (
|
|
|
|
|
# LASTFM_API_KEY, LASTFM_API_SECRET, LASTFM_USERNAME,
|
|
|
|
|
# MIN_PLAYS, RECENT_MONTHS
|
|
|
|
|
#)
|
|
|
|
|
from config import *
|
2025-06-25 13:53:24 +02:00
|
|
|
import logging
|
2025-06-23 10:31:25 +02:00
|
|
|
from datetime import datetime, timedelta
|
2025-06-25 13:53:24 +02:00
|
|
|
from collections import defaultdict
|
2025-06-23 10:31:25 +02:00
|
|
|
|
2025-06-25 13:53:24 +02:00
|
|
|
log = logging.getLogger("LastFmHelpers")
|
|
|
|
|
|
|
|
|
|
LASTFM_NETWORK = None
|
|
|
|
|
try:
|
|
|
|
|
LASTFM_NETWORK = pylast.LastFMNetwork(
|
|
|
|
|
api_key=LASTFM_API_KEY,
|
|
|
|
|
api_secret=LASTFM_API_SECRET,
|
|
|
|
|
username=LASTFM_USERNAME
|
|
|
|
|
)
|
|
|
|
|
log.info("✅ Connected to Last.fm API.")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
log.error(f"❌ Failed to initialize Last.fm network. Check API keys and username: {e}")
|
2025-06-23 10:31:25 +02:00
|
|
|
|
|
|
|
|
def recent_artists():
|
2025-06-25 13:53:24 +02:00
|
|
|
"""Fetches recently played artists from Last.fm, filtered by play count and recency."""
|
|
|
|
|
if not LASTFM_NETWORK:
|
|
|
|
|
log.error("Last.fm network not initialized. Cannot fetch recent artists.")
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
user = LASTFM_NETWORK.get_user(LASTFM_USERNAME)
|
|
|
|
|
since_timestamp = int((datetime.utcnow() - timedelta(days=30 * RECENT_MONTHS)).timestamp())
|
2025-06-23 10:31:25 +02:00
|
|
|
counts = defaultdict(int)
|
2025-06-25 13:53:24 +02:00
|
|
|
|
|
|
|
|
log.info(f"Fetching recent tracks for {LASTFM_USERNAME} since {datetime.fromtimestamp(since_timestamp).strftime('%Y-%m-%d %H:%M:%S')}")
|
|
|
|
|
try:
|
|
|
|
|
for track in user.get_recent_tracks(time_from=since_timestamp, limit=None):
|
|
|
|
|
artist = track.artist
|
|
|
|
|
counts[(artist.name, artist.mbid)] += 1
|
|
|
|
|
except pylast.NetworkError as ne:
|
|
|
|
|
log.error(f"Network error fetching recent tracks: {ne}")
|
|
|
|
|
return []
|
|
|
|
|
except pylast.WSError as wse:
|
|
|
|
|
log.error(f"Last.fm API error fetching recent tracks: {wse}")
|
|
|
|
|
return []
|
|
|
|
|
except Exception as e:
|
|
|
|
|
log.error(f"Unexpected error fetching recent tracks: {e}")
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
return [(name, mbid) for (name, mbid), count in counts.items() if count >= MIN_PLAYS]
|
|
|
|
|
|
|
|
|
|
def get_similar_artists_pylast(artist_mbid, limit):
|
|
|
|
|
"""Fetches artists similar to a given artist from Last.fm."""
|
|
|
|
|
if not LASTFM_NETWORK:
|
|
|
|
|
log.error("Last.fm network not initialized. Cannot fetch similar artists.")
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
artist = LASTFM_NETWORK.get_artist_by_mbid(artist_mbid)
|
|
|
|
|
similar_artists_tuples = artist.get_similar(limit=limit)
|
|
|
|
|
return similar_artists_tuples
|
|
|
|
|
except pylast.WSError as wse:
|
|
|
|
|
log.warning(f"Last.fm API error fetching similar artists for MBID {artist_mbid}: {wse}. Check MBID.")
|
|
|
|
|
return []
|
|
|
|
|
except pylast.NetworkError as ne:
|
|
|
|
|
log.warning(f"Network error fetching similar artists for MBID {artist_mbid}: {ne}")
|
|
|
|
|
return []
|
|
|
|
|
except Exception as e:
|
|
|
|
|
log.warning(f"Could not fetch similar artists for MBID {artist_mbid}: {e}")
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
def get_artist_top_tracks(artist_name, limit=5):
|
|
|
|
|
"""Fetches top tracks for a specific artist from Last.fm."""
|
|
|
|
|
if not LASTFM_NETWORK:
|
|
|
|
|
log.error("Last.fm network not initialized. Cannot fetch top tracks.")
|
|
|
|
|
return []
|
|
|
|
|
try:
|
|
|
|
|
artist = LASTFM_NETWORK.get_artist(artist_name)
|
|
|
|
|
top_tracks = artist.get_top_tracks(limit=limit)
|
|
|
|
|
return [{"artist": track.item.artist.name, "title": track.item.title} for track in top_tracks]
|
|
|
|
|
except pylast.WSError as wse:
|
|
|
|
|
log.warning(f"Last.fm API error fetching top tracks for '{artist_name}': {wse}. Check artist name.")
|
|
|
|
|
return []
|
|
|
|
|
except pylast.NetworkError as ne:
|
|
|
|
|
log.warning(f"Network error fetching top tracks for '{artist_name}': {ne}")
|
|
|
|
|
return []
|
|
|
|
|
except Exception as e:
|
|
|
|
|
log.warning(f"Unexpected error fetching top tracks for '{artist_name}': {e}")
|
2025-06-25 12:31:23 +00:00
|
|
|
return []
|