guitaripod/lastfmkit
A comprehensive Swift SDK for the Last.fm API, designed with protocol-oriented programming and modern Swift features.
Features
- ✅ Complete coverage of Last.fm API endpoints through Cloudflare proxy
- ✅ Secure authentication with credentials managed by Cloudflare Worker
- ✅ Protocol-oriented architecture with clean separation of concerns
- ✅ Async/await support throughout
- ✅ Cross-platform support (macOS, iOS, tvOS, watchOS, Linux)
- ✅ Strongly-typed models with Codable
- ✅ Configurable retry policies and timeout handling
- ✅ Comprehensive error handling
- ✅ Built-in CLI tool for testing all endpoints
Installation
Swift Package Manager
Add the following to your Package.swift file:
dependencies: [
.package(url: "https://github.com/guitaripod/LastFMKit", from: "1.0.0")
]Quick Start
import LastFMKit
// Create a client with default configuration
let client = LastFMClient()
// Or customize the configuration
let client = LastFMClient(
baseURL: "https://lastfm-proxy-worker.guitaripod.workers.dev",
timeout: 30,
retryPolicy: .exponentialBackoff(maxRetries: 3)
)Authentication
LastFMKit supports Last.fm authentication for accessing user-specific endpoints:
// The authentication flow is handled through the Cloudflare Worker
// which manages all API credentials securely
// 1. Get auth URL from the worker
let authURL = try await client.auth.getAuthURL()
// 2. Direct user to auth URL (opens in browser)
// User authorizes and receives a token
// 3. Exchange token for session
let session = try await client.auth.getSession(token: userToken)
// 4. Use authenticated endpoints
let myInfo = try await client.user.getInfo(sessionKey: session.key)Usage Examples
Artist Methods
// Search for artists
let (artists, pagination) = try await client.artist.search(artist: "Radiohead", limit: 10)
// Get artist info
let artist = try await client.artist.getInfo(artist: "Radiohead")
// Get top tracks
let (tracks, _) = try await client.artist.getTopTracks(artist: "Radiohead", limit: 20)
// Get similar artists
let similarArtists = try await client.artist.getSimilar(artist: "Radiohead", limit: 10)
// Get artist correction
if let correction = try await client.artist.getCorrection(artist: "Radioheed") {
print("Did you mean: \(correction.name)?")
}Album Methods
// Search for albums
let (albums, pagination) = try await client.album.search(album: "OK Computer")
// Get album info with tracks
let album = try await client.album.getInfo(artist: "Radiohead", album: "OK Computer")
// Get album tags
let tags = try await client.album.getTopTags(artist: "Radiohead", album: "OK Computer")Track Methods
// Search for tracks
let (tracks, pagination) = try await client.track.search(track: "Creep")
// Get track info
let track = try await client.track.getInfo(artist: "Radiohead", track: "Creep")
// Get similar tracks
let similar = try await client.track.getSimilar(artist: "Radiohead", track: "Creep", limit: 10)User Methods
// Get user info
let user = try await client.user.getInfo(user: "rj")
// Get recent tracks
let (recentTracks, _) = try await client.user.getRecentTracks(user: "rj", limit: 50)
// Get top artists for a time period
let (topArtists, _) = try await client.user.getTopArtists(
user: "rj",
period: .oneMonth,
limit: 10
)
// Get loved tracks
let (lovedTracks, _) = try await client.user.getLovedTracks(user: "rj")Chart Methods
// Get top artists globally
let (topArtists, pagination) = try await client.chart.getTopArtists(limit: 10)
// Get top tracks
let (topTracks, _) = try await client.chart.getTopTracks(limit: 10)
// Get top tags
let (topTags, _) = try await client.chart.getTopTags()Geographic Methods
// Get top artists by country
let (artists, _) = try await client.geo.getTopArtists(country: "United States", limit: 10)
// Get top tracks by country
let (tracks, _) = try await client.geo.getTopTracks(country: "United Kingdom", limit: 10)Tag Methods
// Get tag info
let tagInfo = try await client.tag.getInfo(tag: "rock")
// Get top artists for a tag
let (artists, _) = try await client.tag.getTopArtists(tag: "indie", limit: 20)
// Get similar tags
let similarTags = try await client.tag.getSimilar(tag: "electronic")Error Handling
LastFMKit provides comprehensive error handling:
do {
let artist = try await client.artist.getInfo(artist: "Unknown Artist")
} catch let error as LastFMError {
switch error {
case .invalidParameters(let message):
print("Invalid parameters: \(message)")
case .networkError(let underlyingError):
print("Network error: \(underlyingError)")
case .decodingError:
print("Failed to decode response")
case .rateLimitExceeded:
print("Rate limit exceeded, please try again later")
case .apiError(let code, let message):
print("API error \(code): \(message)")
default:
print("Error: \(error.localizedDescription)")
}
}CLI Tool
LastFMKit includes a comprehensive CLI tool for testing all endpoints:
# Build the CLI tool
swift build
# Authentication
.build/debug/lastfm-cli auth login
.build/debug/lastfm-cli auth status
.build/debug/lastfm-cli auth logout
# Search for artists
.build/debug/lastfm-cli artist search "The Beatles" --limit 5
# Get artist info
.build/debug/lastfm-cli artist info "Radiohead"
# Get user's recent tracks
.build/debug/lastfm-cli user recent-tracks "rj" --limit 10
# Get top artists chart
.build/debug/lastfm-cli chart top-artists --limit 10
# Authenticated user commands
.build/debug/lastfm-cli my info
.build/debug/lastfm-cli my recent-tracks --limit 10
.build/debug/lastfm-cli my top-artists --period 7day
# Get help
.build/debug/lastfm-cli --helpFor a complete list of all available commands and their options, see the CLI Manual.
Configuration
Custom Base URL
let client = LastFMClient(baseURL: "https://your-custom-proxy.com")Timeout Configuration
let client = LastFMClient(timeout: 60) // 60 secondsRetry Policies
// No retries
let client = LastFMClient(retryPolicy: .none)
// Fixed delay retries
let client = LastFMClient(retryPolicy: .fixed(maxRetries: 3, delay: 2.0))
// Exponential backoff (default)
let client = LastFMClient(retryPolicy: .exponentialBackoff(maxRetries: 3, initialDelay: 1.0))Requirements
- Swift 5.9+
- macOS 13.0+ / iOS 16.0+ / tvOS 16.0+ / watchOS 9.0+ / Linux
Architecture
LastFMKit follows a protocol-oriented architecture:
- NetworkClient: Handles all HTTP requests with retry logic and error handling
- BaseAPI: Base class for all API categories
- Strongly-typed models: All responses are decoded into type-safe Swift structs
- Async/await: Modern concurrency throughout the SDK
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
LastFMKit is available under the MIT license. See the LICENSE file for more info.
Package Metadata
Repository: guitaripod/lastfmkit
Default branch: master
README: README.md