'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var crypto = require('crypto'); class LastFm { #debug; #apiKey; #apiSecret; #username; #password; #sessionKey; constructor(opts) { this.#debug = opts?.debug ?? false; if (opts?.apiKey) { this.#apiKey = opts.apiKey; } if (opts?.apiSecret) { this.#apiSecret = opts.apiSecret; } if (opts?.username) { this.#username = opts.username; } if (opts?.password) { this.#password = opts.password; } if (opts?.sessionKey) { this.#sessionKey = opts.sessionKey; } } static #sendErr(msg) { // handles error checking within library const errMsg = { error: 6, message: msg, success: false }; return new Promise((_, reject) => { reject(errMsg); }); } static #PostRequestToString(params) { return Object.entries(params) .sort((a, b) => a[0].localeCompare(b[0])) .reduce((sig, [key, value]) => key !== "format" ? value instanceof Array ? value.reduce((newSig, item, i) => `${newSig}[${i}]${item}`, sig) : `${sig}${key}${typeof value !== "undefined" ? value : ""}` : sig, ""); } static #createSignature(params, secret) { // create signature by hashing const sig = this.#PostRequestToString(params) + secret; return crypto.createHash("md5").update(sig, "utf8").digest("hex"); } static #urlBuilder(url, params) { Object.entries(params).forEach(([key, value]) => { url.searchParams.append(key, value?.toString() ?? ""); }); return url.toString(); } async #getData(params, name) { const queryUrl = new URL("http://ws.audioscrobbler.com/2.0/"); const queryParams = { ...params, api_key: this.#apiKey, format: "json", }; try { const res = await fetch(LastFm.#urlBuilder(queryUrl, queryParams), { method: "GET", headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", }, }); if (res.ok) { const json = (await res.json()); json[name].success = true; return json[name]; } throw new Error("Error communicating with last.fm"); } catch (e) { if (typeof e === "string") { if (this.#debug) console.log(`Exception: ${e}`); return { success: false, error: new Error(e) }; } else if (e instanceof Error) { if (this.#debug) console.log(`Exception: ${e.message}`); return { success: false, error: e }; } else { if (this.#debug) console.log(`Unknown exception`); return { success: false, error: new Error("Unknown error") }; } } } async #postData(params) { if (!this.#apiKey) throw new Error("No api key available"); if (!this.#apiSecret) throw new Error("No api secret available"); const qs = { ...params, api_key: this.#apiKey, format: "json", }; if (this.#sessionKey) qs.sk = this.#sessionKey; qs.api_sig = LastFm.#createSignature(qs, this.#apiSecret); try { const res = await fetch("https://ws.audioscrobbler.com/2.0/", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", }, // TS will not see PostParams as Record because it has optional fields body: new URLSearchParams(qs), }); if (res.ok) { const json = (await res.json()); json.success = true; return json; } throw new Error("Error communicating with last.fm"); } catch (e) { if (typeof e === "string") { if (this.#debug) console.log(`Exception: ${e}`); return { success: false, error: new Error(e) }; } else if (e instanceof Error) { if (this.#debug) console.log(`Exception: ${e.message}`); return { success: false, error: e }; } else { if (this.#debug) console.log(`Unknown exception`); return { success: false, error: new Error("Unknown error") }; } } } async #get(qs, name) { return this.#getData(qs, name); } #post(qs) { return this.#postData(qs); } async auth_getMobileSession() { const qs = { method: "auth.getMobileSession", username: this.#username, password: this.#password, }; try { const res = await this.#postData(qs); if (!res.success) throw new Error("Error connecting to last.fm"); this.#sessionKey = res.session.key; return res.session; } catch (e) { return LastFm.#sendErr(e); } } // album methods album_addTags(qs) { if (!qs?.artist || !qs.album || !qs.tags) { return LastFm.#sendErr("Missing required params"); } return this.#post({ ...qs, method: "album.addTags" }); } album_getInfo(qs) { if ((!qs?.artist || !qs.album) && !qs?.mbid) { return LastFm.#sendErr("Missing required params"); } return this.#get({ autocorrect: "1", ...qs, method: "album.getInfo" }, "album"); } album_getTags(qs) { if ((!qs?.artist || !qs.album) && !qs?.mbid) { return LastFm.#sendErr("Missing required params"); } return this.#get({ autocorrect: "1", ...qs, method: "album.getTags" }, "tags"); } album_getTopTags(qs) { if ((!qs?.artist || !qs.album) && !qs?.mbid) { return LastFm.#sendErr("Missing required params"); } return this.#get({ autocorrect: "1", ...qs, method: "album.getTopTags" }, "toptags"); } album_removeTag(qs) { if (!qs?.artist || !qs.album || !qs.tag) { return LastFm.#sendErr("Missing required params"); } return this.#post({ ...qs, method: "album.removeTag" }); } album_search(qs) { if (!qs?.album) { return LastFm.#sendErr("Missing album param"); } return this.#get({ autocorrect: "1", ...qs, method: "album.search" }, "results"); } // Artist methods artist_addTags(qs) { if (!qs?.artist || !qs.tags) { return LastFm.#sendErr("Missing required parameters"); } return this.#post({ ...qs, method: "artist.addTags" }); } artist_getCorrection(qs) { if (!qs?.artist) { return LastFm.#sendErr("Missing Artist"); } return this.#get({ ...qs, method: "artist.getCorrection" }, "corrections"); } artist_getInfo(qs) { if (!qs?.artist && !qs?.mbid) { return LastFm.#sendErr("Missing both artist and mbid"); } return this.#get({ autocorrect: "1", ...qs, method: "artist.getInfo" }, "artist"); } artist_getSimilar(qs) { if (!qs?.artist && !qs?.mbid) { return LastFm.#sendErr("Missing both artist and mbid"); } return this.#get({ autocorrect: "1", ...qs, method: "artist.getSimilar" }, "similarartists"); } artist_getTags(qs) { if (!qs || (!qs.artist && !qs.mbid) || !qs.user) { return LastFm.#sendErr("Missing both artist and mbid"); } return this.#get({ autocorrect: "1", ...qs, method: "artist.getTags" }, "tags"); } artist_getTopAlbums(qs) { if (!qs?.artist && !qs?.mbid) { return LastFm.#sendErr("Missing both artist and mbid"); } return this.#get({ autocorrect: "1", ...qs, method: "artist.getTopAlbums" }, "topalbums"); } artist_getTopTags(qs) { if (!qs?.artist && !qs?.mbid) { return LastFm.#sendErr("Missing both artist and mbid"); } return this.#get({ autocorrect: "1", ...qs, method: "artist.getTopTags" }, "toptags"); } artist_getTopTracks(qs) { if (!qs?.artist && !qs?.mbid) { return LastFm.#sendErr("Missing both artist and mbid"); } return this.#get({ autocorrect: "1", ...qs, method: "artist.getTopTracks" }, "toptracks"); } artist_removeTag(qs) { if (!qs?.artist || !qs.tag) { return LastFm.#sendErr("Missing required parameters"); } return this.#post({ ...qs, method: "artist.removeTag" }); } artist_search(qs) { if (!qs?.artist) { return LastFm.#sendErr("Missing artist to search"); } return this.#get({ autocorrect: "1", ...qs, method: "artist.search" }, "results"); } // Chart Methods chart_getTopArtists(qs) { return this.#get({ autocorrect: "1", ...qs, method: "chart.getTopArtists" }, "artists"); } chart_getTopTags(qs) { return this.#get({ autocorrect: "1", ...qs, method: "chart.getTopTags" }, "tags"); } chart_getTopTracks(qs) { return this.#get({ autocorrect: "1", ...qs, method: "chart.getTopTracks" }, "tracks"); } // Geo Methods geo_getTopArtists(qs) { if (!qs?.country) { return LastFm.#sendErr("Missing country"); } return this.#get({ autocorrect: "1", ...qs, method: "geo.getTopArtists" }, "topartists"); } geo_getTopTracks(qs) { if (!qs?.country) { return LastFm.#sendErr("Missing country"); } return this.#get({ autocorrect: "1", ...qs, method: "geo.getTopTracks" }, "tracks"); } // Library Methods library_getArtists(qs) { if (!qs?.user) { return LastFm.#sendErr("Missing username"); } return this.#get({ autocorrect: "1", ...qs, method: "library.getArtists" }, "artists"); } // Tag Methods tag_getInfo(qs) { if (!qs?.tag) { return LastFm.#sendErr("No tag given"); } return this.#get({ ...qs, method: "tag.getInfo" }, "tag"); } tag_getSimilar(qs) { if (!qs?.tag) { return LastFm.#sendErr("No tag given"); } return this.#get({ ...qs, method: "tag.getSimilar" }, "similartags"); } tag_getTopAlbums(qs) { if (!qs?.tag) { return LastFm.#sendErr("No tag given"); } return this.#get({ ...qs, method: "tag.getTopAlbums" }, "albums"); } tag_getTopArtists(qs) { if (!qs?.tag) { return LastFm.#sendErr("No tag given"); } return this.#get({ ...qs, method: "tag.getTopArtists" }, "topartists"); } tag_getTopTags(qs) { return this.#get({ ...qs, method: "tag.getTopTags" }, "toptags"); } tag_getTopTracks(qs) { if (!qs?.tag) { return LastFm.#sendErr("No tag given"); } return this.#get({ ...qs, method: "tag.getTopTracks" }, "tracks"); } tag_getWeeklyChartList(qs) { if (!qs?.tag) { return LastFm.#sendErr("No tag given"); } return this.#get({ ...qs, method: "tag.getWeeklyChartList" }, "weeklychartlist"); } // Track methods track_addTags(qs) { if (!qs?.artist || !qs.track || !qs.tags) { return LastFm.#sendErr("Missing required params"); } return this.#post({ ...qs, method: "track.addTags" }); } track_getCorrection(qs) { if (!qs?.track || !qs.artist) { return LastFm.#sendErr("Missing required params"); } return this.#get({ ...qs, method: "track.getCorrection" }, "corrections"); } track_getInfo(qs) { if ((!qs?.track || !qs.artist) && !qs?.mbid) { return LastFm.#sendErr("Missing required params"); } return this.#get({ autocorrect: "1", ...qs, method: "track.getInfo" }, "track"); } track_getSimilar(qs) { if ((!qs?.track || !qs.artist) && !qs?.mbid) { return LastFm.#sendErr("Missing required params"); } return this.#get({ autocorrect: "1", ...qs, method: "track.getSimilar" }, "similartracks"); } track_getTags(qs) { if ((!qs?.track || !qs.artist) && !qs?.mbid) { return LastFm.#sendErr("Missing required params"); } return this.#get({ autocorrect: "1", ...qs, method: "track.getTags" }, "tags"); } track_getTopTags(qs) { if ((!qs?.track || !qs.artist) && !qs?.mbid) { return LastFm.#sendErr("Missing required params"); } return this.#get({ autocorrect: "1", ...qs, method: "track.getTopTags" }, "toptags"); } track_love(qs) { if (!qs?.track || !qs.artist) { return LastFm.#sendErr("Missing required params"); } return this.#post({ ...qs, method: "track.love" }); } track_removeTag(qs) { if (!qs?.artist || !qs.track || !qs.tag) { return LastFm.#sendErr("Missing required params"); } return this.#post({ ...qs, method: "track.removeTag" }); } track_scrobble(qs) { if (!qs?.artist || !qs.track || !qs.timestamp) { return LastFm.#sendErr("Missing required params"); } return this.#post({ ...qs, method: "track.scrobble" }); } track_search(qs) { if (!qs?.track) { return LastFm.#sendErr("Missing track for search"); } return this.#get({ autocorrect: "1", ...qs, method: "track.search" }, "results"); } track_unlove(qs) { if (!qs?.track || !qs.artist) { return LastFm.#sendErr("Missing track or artist"); } return this.#post({ ...qs, method: "track.unlove" }); } track_updateNowPlaying(qs) { if (!qs?.track || !qs.artist) { return LastFm.#sendErr("Missing track or artist"); } return this.#post({ ...qs, method: "track.updateNowPlaying", }); } // User Methods user_getFriends(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getFriends" }, "friends"); } user_getInfo(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getInfo" }, "user"); } user_getLovedTracks(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getLovedTracks" }, "lovedtracks"); } user_getPersonalTags(qs) { if (!qs?.tag) { return LastFm.#sendErr("Missing tag"); } if (qs.tag && !qs.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } qs.user = this.#username; } return this.#get({ ...qs, method: "user.getPersonalTags" }, "taggings"); } user_getRecentTracks(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getRecentTracks" }, "recenttracks"); } user_getTopAlbums(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getTopAlbums" }, "topalbums"); } user_getTopArtists(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getTopArtists" }, "topartists"); } user_getTopTags(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getTopTags" }, "toptags"); } user_getTopTracks(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getTopTracks" }, "toptracks"); } user_getWeeklyAlbumChart(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getWeeklyAlbumChart" }, "weeklyalbumchart"); } user_getWeeklyArtistChart(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getWeeklyArtistChart" }, "weeklyartistchart"); } user_getWeeklyChartList(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getWeeklyChartList" }, "weeklychartlist"); } user_getWeeklyTrackChart(qs) { if (!qs?.user) { if (!this.#username) { return LastFm.#sendErr("Missing user"); } if (!qs) { qs = { user: this.#username }; } else { qs.user = this.#username; } } return this.#get({ ...qs, method: "user.getWeeklyTrackChart" }, "weeklytrackchart"); } } exports.LastFmImageSize = void 0; (function (LastFmImageSize) { LastFmImageSize["SMALL"] = "small"; LastFmImageSize["MEDIUM"] = "medium"; LastFmImageSize["LARGE"] = "large"; LastFmImageSize["EXTRALARGE"] = "extralarge"; LastFmImageSize["MEGA"] = "mega"; })(exports.LastFmImageSize || (exports.LastFmImageSize = {})); exports.Period = void 0; (function (Period) { Period["OVERALL"] = "overall"; Period["WEEK"] = "7day"; Period["MONTH"] = "1month"; Period["THREE_MONTH"] = "3month"; Period["SIX_MONTH"] = "6month"; Period["YEAR"] = "12month"; })(exports.Period || (exports.Period = {})); exports.SearchType = void 0; (function (SearchType) { SearchType["ALBUM"] = "album"; SearchType["ARTIST"] = "artist"; SearchType["TRACK"] = "track"; })(exports.SearchType || (exports.SearchType = {})); exports.default = LastFm; //# sourceMappingURL=index.cjs.map