A Python interface to Last.fm and Libre.fm for music data, scrobbling, and social features.
npx @tessl/cli install tessl/pypi-pylast@5.5.0A comprehensive Python interface to Last.fm and Libre.fm APIs that provides full object-oriented access to music data, scrobbling functionality, user profiles, and social music networking features. PyLast offers complete coverage of Last.fm web services including music discovery, recommendations, user statistics, and social interactions with caching and proxy support.
pip install pylasthelp(pylast) or see tests/ for examplesimport pylastMain entry points:
from pylast import LastFMNetwork, LibreFMNetworkCommon objects and utilities:
from pylast import (
Artist, Track, Album, User, AuthenticatedUser,
SessionKeyGenerator, md5,
WSError, PyLastError
)import pylast
# Initialize network with API credentials
API_KEY = "your_api_key"
API_SECRET = "your_api_secret"
username = "your_username"
password_hash = pylast.md5("your_password")
network = pylast.LastFMNetwork(
api_key=API_KEY,
api_secret=API_SECRET,
username=username,
password_hash=password_hash
)
# Get music objects
artist = network.get_artist("Iron Maiden")
track = network.get_track("Iron Maiden", "The Nomad")
album = network.get_album("Iron Maiden", "Brave New World")
# Basic music data access
print(f"Artist: {artist.get_name()}")
print(f"Play count: {artist.get_playcount()}")
print(f"Similar artists: {[a.item.get_name() for a in artist.get_similar(limit=5)]}")
# User interactions
track.love() # Love a track
track.add_tags(("metal", "progressive")) # Add tags
# Scrobbling
network.scrobble(
artist="Iron Maiden",
title="The Nomad",
timestamp=int(time.time())
)
# User data
user = network.get_authenticated_user()
recent_tracks = user.get_recent_tracks(limit=10)
for played_track in recent_tracks:
print(f"{played_track.track.get_artist()} - {played_track.track.get_title()}")PyLast provides a comprehensive object-oriented interface to Last.fm APIs:
This design enables full integration with Last.fm's music database and social networking features while providing caching, proxy support, and rate limiting for production use.
Core network initialization, authentication methods, session management, and configuration options including proxy and caching support.
class LastFMNetwork:
def __init__(self, api_key="", api_secret="", session_key="", username="", password_hash="", token=""): ...
class LibreFMNetwork:
def __init__(self, api_key="", api_secret="", session_key="", username="", password_hash=""): ...
class SessionKeyGenerator:
def __init__(self, network): ...
def get_web_auth_url(self) -> str: ...
def get_session_key(self, username: str, password_hash: str) -> str: ...Comprehensive music entity objects (Artist, Track, Album) with metadata access, social features, statistics, and content discovery capabilities.
class Artist:
def __init__(self, name: str, network, username=None, info=None): ...
def get_name(self, properly_capitalized=False) -> str: ...
def get_similar(self, limit=None) -> list[SimilarItem]: ...
def get_top_tracks(self, limit=None, cacheable=True) -> list[TopItem]: ...
class Track:
def __init__(self, artist: str, title: str, network, username=None, info=None): ...
def love(self) -> None: ...
def get_similar(self, limit=None) -> list[SimilarItem]: ...
class Album:
def __init__(self, artist: str, title: str, network, username=None, info=None): ...
def get_tracks(self) -> list[Track]: ...User profiles, listening history, social interactions, library access, and community features including friends, tags, and recommendations.
class User:
def __init__(self, user_name: str, network): ...
def get_recent_tracks(self, limit=50, cacheable=True, stream=True, from_date=None, to_date=None) -> list[PlayedTrack]: ...
def get_loved_tracks(self, limit=50, cacheable=True) -> list[LovedTrack]: ...
def get_top_artists(self, period="overall", limit=None, cacheable=True) -> list[TopItem]: ...
class AuthenticatedUser(User):
def __init__(self, network): ...
class Library:
def __init__(self, user, network): ...
def get_artists(self, limit=50, cacheable=True, stream=True) -> list[LibraryItem]: ...Music search capabilities, content discovery, geographic data, and tag-based music exploration with pagination support.
class ArtistSearch:
def __init__(self, artist_name: str, network): ...
def get_next_page(self) -> list[Artist]: ...
def get_total_result_count(self) -> int: ...
class TrackSearch:
def __init__(self, artist_name: str, track_name: str, network): ...
def get_next_page(self) -> list[Track]: ...
class AlbumSearch:
def __init__(self, album_name: str, network): ...
def get_next_page(self) -> list[Album]: ...
class Country:
def __init__(self, name: str, network): ...
def get_top_artists(self, limit=None, cacheable=True) -> list[TopItem]: ...
class Tag:
def __init__(self, name: str, network): ...
def get_top_artists(self, limit=None, cacheable=True) -> list[TopItem]: ...Music scrobbling, now playing updates, listening data management, and play count tracking with timestamp support.
# Network scrobbling methods
def scrobble(self, artist: str, title: str, timestamp: int, album=None, track_number=None, mbid=None, duration=None) -> None: ...
def scrobble_many(self, tracks: list) -> None: ...
def update_now_playing(self, artist: str, title: str, album=None, track_number=None, mbid=None, duration=None) -> None: ...from collections import namedtuple
TopItem = namedtuple('TopItem', ['item', 'weight'])
SimilarItem = namedtuple('SimilarItem', ['item', 'match'])
LibraryItem = namedtuple('LibraryItem', ['item', 'playcount', 'tagcount'])
PlayedTrack = namedtuple('PlayedTrack', ['track', 'album', 'playback_date', 'timestamp'])
LovedTrack = namedtuple('LovedTrack', ['track', 'date', 'timestamp'])
ImageSizes = namedtuple('ImageSizes', ['original', 'large', 'largesquare', 'medium', 'small', 'extralarge'])
Image = namedtuple('Image', ['title', 'url', 'dateadded', 'format', 'owner', 'sizes', 'votes'])# Time periods for statistics
PERIOD_OVERALL = "overall"
PERIOD_7DAYS = "7day"
PERIOD_1MONTH = "1month"
PERIOD_3MONTHS = "3month"
PERIOD_6MONTHS = "6month"
PERIOD_12MONTHS = "12month"
# Image sizes
SIZE_SMALL = 0
SIZE_MEDIUM = 1
SIZE_LARGE = 2
SIZE_EXTRA_LARGE = 3
SIZE_MEGA = 4
# Language domains
DOMAIN_ENGLISH = 0
DOMAIN_GERMAN = 1
DOMAIN_SPANISH = 2
DOMAIN_FRENCH = 3
DOMAIN_ITALIAN = 4
DOMAIN_POLISH = 5
DOMAIN_PORTUGUESE = 6
DOMAIN_SWEDISH = 7
DOMAIN_TURKISH = 8
DOMAIN_RUSSIAN = 9
DOMAIN_JAPANESE = 10
DOMAIN_CHINESE = 11
# Scrobble source constants
SCROBBLE_SOURCE_USER = "P"
SCROBBLE_SOURCE_NON_PERSONALIZED_BROADCAST = "R"
SCROBBLE_SOURCE_PERSONALIZED_BROADCAST = "E"
SCROBBLE_SOURCE_LASTFM = "L"
SCROBBLE_SOURCE_UNKNOWN = "U"
# Scrobble mode constants
SCROBBLE_MODE_PLAYED = ""
SCROBBLE_MODE_LOVED = "L"
SCROBBLE_MODE_BANNED = "B"
SCROBBLE_MODE_SKIPPED = "S"
# Image ordering options
IMAGES_ORDER_POPULARITY = "popularity"
IMAGES_ORDER_DATE = "dateadded"
# Utility function
def md5(text: str) -> str: ...class PyLastError(Exception):
"""Base exception for PyLast"""
class WSError(PyLastError):
"""Web service related errors with status codes"""
def get_id(self) -> int:
"""Returns the error status code"""
class MalformedResponseError(PyLastError):
"""Malformed response from music network"""
class NetworkError(PyLastError):
"""Network connection errors"""
# Error status constants
STATUS_INVALID_SERVICE = 2
STATUS_INVALID_METHOD = 3
STATUS_AUTH_FAILED = 4
STATUS_INVALID_FORMAT = 5
STATUS_INVALID_PARAMS = 6
STATUS_INVALID_RESOURCE = 7
STATUS_OPERATION_FAILED = 8
STATUS_INVALID_SK = 9
STATUS_INVALID_API_KEY = 10
STATUS_OFFLINE = 11
STATUS_SUBSCRIBERS_ONLY = 12
STATUS_INVALID_SIGNATURE = 13
STATUS_TOKEN_UNAUTHORIZED = 14
STATUS_TOKEN_EXPIRED = 15
STATUS_TEMPORARILY_UNAVAILABLE = 16
STATUS_LOGIN_REQUIRED = 17
STATUS_TRIAL_EXPIRED = 18
STATUS_NOT_ENOUGH_CONTENT = 20
STATUS_NOT_ENOUGH_MEMBERS = 21
STATUS_NOT_ENOUGH_FANS = 22
STATUS_NOT_ENOUGH_NEIGHBOURS = 23
STATUS_NO_PEAK_RADIO = 24
STATUS_RADIO_NOT_FOUND = 25
STATUS_API_KEY_SUSPENDED = 26
STATUS_DEPRECATED = 27
STATUS_RATE_LIMIT_EXCEEDED = 29