UNPKG

lastfm-api-lib

Version:

A TypeScript library for interacting with the Last.fm API

455 lines (448 loc) 10.3 kB
// src/httpClient.ts import axios from "axios"; var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]); var LastFmHttpClient = class { client; apiKey; baseURL = "https://ws.audioscrobbler.com/2.0/"; constructor(apiKey) { this.apiKey = apiKey || ""; this.client = axios.create({ baseURL: this.baseURL, timeout: 1e4, headers: { "User-Agent": "lastfm-api-lib/1.0.0", "Accept": "application/json" } }); this.client.interceptors.response.use( (response) => response, (error) => this.handleResponseError(error) ); } /** * Set API key for requests */ setApiKey(apiKey) { this.apiKey = apiKey; } /** * Clear the API key */ clearApiKey() { this.apiKey = ""; } /** * Make a request to the Last.fm API */ async request(method, params = {}, options = {}) { if (!this.apiKey) { throw new Error("API key is required"); } const requestParams = { method, api_key: this.apiKey, format: "json", ...params }; const config = { method: options.method || "GET", params: requestParams, headers: options.headers }; try { const response = await this.client.request(config); if (response.data?.error) { const error = new Error(response.data.message || "Last.fm API error"); error.code = response.data.error; error.status = response.status; throw error; } return response.data; } catch (error) { if (error.isAxiosError) { const lastFmError = new Error( error.response?.data?.message || error.message || "Request failed" ); lastFmError.status = error.response?.status; lastFmError.response = error.response?.data; throw lastFmError; } throw error; } } /** * Handle response errors with retries for certain status codes */ async handleResponseError(error) { if (error.response?.status && RETRYABLE_STATUS_CODES.has(error.response.status) && error.config && !error.config._retryCount) { error.config._retryCount = 1; if (error.response.status === 429) { await this.delay(1e3); } return this.client.request(error.config); } return Promise.reject(error); } /** * Delay helper for rate limiting */ delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } /** * Get the HTTP client instance */ getHttpClient() { return this.client; } }; // src/endpoints/baseEndpoint.ts var BaseEndpoint = class { httpClient; constructor(httpClient) { this.httpClient = httpClient; } /** * Make a request to the API */ async request(method, params = {}) { return this.httpClient.request(method, params); } /** * Clean up undefined/null parameters */ cleanParams(params) { const cleaned = {}; for (const [key, value] of Object.entries(params)) { if (value !== void 0 && value !== null && value !== "") { cleaned[key] = value; } } return cleaned; } }; // src/endpoints/artist.ts var ArtistEndpoints = class extends BaseEndpoint { /** * Get artist correction */ async getCorrection(artist) { const params = this.cleanParams({ artist }); return this.request("artist.getCorrection", params); } /** * Get artist information */ async getInfo(artist, options = {}) { const params = this.cleanParams({ artist, ...options }); return this.request("artist.getInfo", params); } /** * Get similar artists */ async getSimilar(artist, options = {}) { const params = this.cleanParams({ artist, ...options }); return this.request("artist.getSimilar", params); } /** * Get top albums for an artist */ async getTopAlbums(artist, options = {}) { const params = this.cleanParams({ artist, ...options }); return this.request("artist.getTopAlbums", params); } /** * Get top tags for an artist */ async getTopTags(artist, options = {}) { const params = this.cleanParams({ artist, ...options }); return this.request("artist.getTopTags", params); } /** * Get top tracks for an artist */ async getTopTracks(artist, options = {}) { const params = this.cleanParams({ artist, ...options }); return this.request("artist.getTopTracks", params); } /** * Search for an artist */ async search(artist, options = {}) { const params = this.cleanParams({ artist, ...options }); return this.request("artist.search", params); } }; // src/endpoints/album.ts var AlbumEndpoints = class extends BaseEndpoint { /** * Get album information */ async getInfo(artist, album, options = {}) { const params = this.cleanParams({ artist, album, ...options }); return this.request("album.getInfo", params); } /** * Get top tags for an album */ async getTopTags(artist, album, options = {}) { const params = this.cleanParams({ artist, album, ...options }); return this.request("album.getTopTags", params); } /** * Search for an album */ async search(album, options = {}) { const params = this.cleanParams({ album, ...options }); return this.request("album.search", params); } }; // src/endpoints/track.ts var TrackEndpoints = class extends BaseEndpoint { /** * Get track correction */ async getCorrection(artist, track) { const params = this.cleanParams({ artist, track }); return this.request("track.getCorrection", params); } /** * Get track information */ async getInfo(artist, track, options = {}) { const params = this.cleanParams({ artist, track, ...options }); return this.request("track.getInfo", params); } /** * Get similar tracks */ async getSimilar(artist, track, options = {}) { const params = this.cleanParams({ artist, track, ...options }); return this.request("track.getSimilar", params); } /** * Get top tags for a track */ async getTopTags(artist, track, options = {}) { const params = this.cleanParams({ artist, track, ...options }); return this.request("track.getTopTags", params); } /** * Search for a track */ async search(track, options = {}) { const params = this.cleanParams({ track, ...options }); return this.request("track.search", params); } }; // src/endpoints/tag.ts var TagEndpoints = class extends BaseEndpoint { /** * Get tag information */ async getInfo(tag, options = {}) { const params = this.cleanParams({ tag, ...options }); return this.request("tag.getInfo", params); } /** * Get similar tags */ async getSimilar(tag) { const params = this.cleanParams({ tag }); return this.request("tag.getSimilar", params); } /** * Get top albums for a tag */ async getTopAlbums(tag, options = {}) { const params = this.cleanParams({ tag, ...options }); return this.request("tag.getTopAlbums", params); } /** * Get top artists for a tag */ async getTopArtists(tag, options = {}) { const params = this.cleanParams({ tag, ...options }); return this.request("tag.getTopArtists", params); } /** * Get top tracks for a tag */ async getTopTracks(tag, options = {}) { const params = this.cleanParams({ tag, ...options }); return this.request("tag.getTopTracks", params); } /** * Get top tags */ async getTopTags() { return this.request("tag.getTopTags"); } }; // src/endpoints/chart.ts var ChartEndpoints = class extends BaseEndpoint { /** * Get top artists chart */ async getTopArtists(options = {}) { const params = this.cleanParams(options); return this.request("chart.getTopArtists", params); } /** * Get top tracks chart */ async getTopTracks(options = {}) { const params = this.cleanParams(options); return this.request("chart.getTopTracks", params); } /** * Get top tags chart */ async getTopTags(options = {}) { const params = this.cleanParams(options); return this.request("chart.getTopTags", params); } }; // src/main.ts var ENDPOINT_CLASSES = { artist: ArtistEndpoints, album: AlbumEndpoints, track: TrackEndpoints, tag: TagEndpoints, chart: ChartEndpoints }; var LastFm = class { httpClient; // Endpoint groups artist; album; track; tag; chart; constructor(apiKey) { if (apiKey && !this.isValidApiKeyFormat(apiKey)) { console.warn("LastFm: API key format appears invalid"); } this.httpClient = new LastFmHttpClient(apiKey); this.initializeEndpoints(); } /** * Initialize all endpoint groups */ initializeEndpoints() { for (const [name, EndpointClass] of Object.entries(ENDPOINT_CLASSES)) { ; this[name] = new EndpointClass(this.httpClient); } } /** * Basic API key format validation */ isValidApiKeyFormat(apiKey) { return typeof apiKey === "string" && /^[a-f0-9]{32}$/i.test(apiKey); } /** * Set API key for API requests */ setApiKey(apiKey) { this.httpClient.setApiKey(apiKey); } /** * Clear the API key */ clearApiKey() { this.httpClient.clearApiKey(); } /** * Make a raw API request */ async request(method, params = {}) { return this.httpClient.request(method, params); } /** * Get the HTTP client instance for advanced usage */ getHttpClient() { return this.httpClient; } /** * Clean up resources and clear API key */ destroy() { this.clearApiKey(); Object.values(ENDPOINT_CLASSES).forEach((_, key) => { const endpoint = this[Object.keys(ENDPOINT_CLASSES)[key]]; if (endpoint && typeof endpoint.cleanup === "function") { endpoint.cleanup(); } }); } }; export { AlbumEndpoints, ArtistEndpoints, ChartEndpoints, LastFm, LastFmHttpClient, TagEndpoints, TrackEndpoints, LastFm as default }; //# sourceMappingURL=index.js.map