Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@solely/simple-fm

Package Overview
Dependencies
Maintainers
1
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@solely/simple-fm - npm Package Compare versions

Comparing version 1.5.3 to 1.6.0

dist/params/index.d.ts

2

dist/base.d.ts

@@ -6,3 +6,3 @@ import { LastFMArgument } from './request.js';

constructor(key: string, userAgent?: string);
protected sendRequest<T = unknown>(params: LastFMArgument): Promise<T>;
protected sendRequest<T>(params: LastFMArgument): Promise<T>;
}

@@ -0,1 +1,2 @@

import { pkg } from './utils/package.js';
import { LastFMRequest } from './request.js';

@@ -5,3 +6,3 @@ export default class Base {

userAgent;
constructor(key, userAgent = `simple-fm - a simple Last.fm wrapper written in TypeScript (GitHub: https://github.com/solelychloe/simple-fm)`) {
constructor(key, userAgent = `simple-fm v${pkg.version} - a simple Last.fm wrapper written in TypeScript (https://github.com/solelychloe/simple-fm)`) {
this.key = key;

@@ -11,5 +12,5 @@ this.userAgent = userAgent;

async sendRequest(params) {
const response = await new LastFMRequest(this.key, this.userAgent, params).get();
const response = await new LastFMRequest(this.key, this.userAgent, params).execute();
return response;
}
}
import Base from '../base.js';
import type { AlbumGetInfoType, AlbumGetTopTagsType, AlbumSearchType } from '../types/index.js';
import type { AlbumGetInfoParams, AlbumGetTopTagsParams, AlbumSearchParams } from '../params/album.params.js';
import type { AlbumGetInfoParams, AlbumGetTopTagsParams, AlbumSearchParams } from '../params/index.js';
import type { AlbumGetInfoType, AlbumGetTopTagsType, AlbumSearchType } from '../typings/index.js';
export default class Album extends Base {

@@ -5,0 +5,0 @@ /**

@@ -1,2 +0,2 @@

import { convertImageSizes, convertURL } from '../utils/convert.js';
import { convertImageSizes, createLastFmURL } from '../utils/convert.js';
import Base from '../base.js';

@@ -11,12 +11,10 @@ export default class Album extends Base {

async getInfo(params) {
const { album, album: { tracks: { track }, tags: { tag }, }, } = await this.sendRequest({
const { album, album: { tracks: { track: trackMatches }, tags: { tag: tagMatches }, }, } = await this.sendRequest({
method: 'album.getInfo',
artist: params.artist,
album: params.album,
username: params.username,
...params,
});
const returnTrack = (track) => ({
const createTrackObject = (track) => ({
rank: Number(track['@attr'].rank),
name: track.name,
duration: Number(track.duration) || null,
duration: Number(track.duration),
url: track.url,

@@ -26,5 +24,6 @@ });

name: album.name,
mbid: album.mbid,
artist: {
name: album.artist,
url: `https://www.last.fm/music/${convertURL(album.artist)}`,
url: createLastFmURL('artist', album.artist),
},

@@ -36,11 +35,10 @@ stats: {

userStats: {
userPlayCount: (params.username && Number(album.userplaycount)) || null,
userPlayCount: album.userplaycount,
},
tags: tag.map((tag) => ({
name: tag.name,
url: tag.url,
})),
tracks: Array.isArray(track) ? track.map((track) => returnTrack(track)) : returnTrack(track),
tags: tagMatches.map((tag) => ({ name: tag.name, url: tag.url })),
tracks: Array.isArray(trackMatches)
? trackMatches.map((track) => createTrackObject(track))
: createTrackObject(trackMatches),
url: album.url,
image: convertImageSizes(album.image) || null,
image: convertImageSizes(album.image),
};

@@ -54,6 +52,5 @@ }

async getTopTags(params) {
const { toptags: { tag, '@attr': attr }, } = await this.sendRequest({
const { toptags: { tag: tagMatches, '@attr': attr }, } = await this.sendRequest({
method: 'album.getTopTags',
artist: params.artist,
album: params.album,
...params,
});

@@ -64,5 +61,5 @@ return {

name: attr.artist,
url: `https://www.last.fm/music/${convertURL(attr.artist)}`,
url: createLastFmURL('artist', attr.artist),
},
tags: tag.map((tag) => ({
tags: tagMatches.map((tag) => ({
count: tag.count,

@@ -81,5 +78,5 @@ name: tag.name,

async search(params) {
const { results, results: { albummatches: { album }, }, } = await this.sendRequest({
const { results, results: { albummatches: { album: albumMatches }, }, } = await this.sendRequest({
method: 'album.search',
album: params.album,
...params,
limit: params.limit ?? 30,

@@ -95,10 +92,11 @@ page: params.page ?? 1,

},
albums: album.map((album) => ({
albums: albumMatches.map((album) => ({
name: album.name,
mbid: album.mbid === '' ? undefined : album.mbid,
artist: {
name: album.artist,
url: `https://www.last.fm/music/${convertURL(album.artist)}`,
url: createLastFmURL('artist', album.artist),
},
url: album.url,
image: convertImageSizes(album.image) || null,
image: convertImageSizes(album.image),
})),

@@ -105,0 +103,0 @@ };

import Base from '../base.js';
import type { ArtistGetInfoType, ArtistSearchType, ArtistGetSimilarType, ArtistGetTopAlbumsType, ArtistGetTopTagsType, ArtistGetTopTracksType } from '../types/index.js';
import type { ArtistGetInfoParams, ArtistGetSimilarParams, ArtistGetTopAlbumsParams, ArtistGetTopTagsParams, ArtistGetTopTracksParams, ArtistSearchParams } from '../params/artist.params.js';
import type { ArtistGetInfoParams, ArtistGetSimilarParams, ArtistGetTopAlbumsParams, ArtistGetTopTagsParams, ArtistGetTopTracksParams, ArtistSearchParams } from '../params/index.js';
import type { ArtistGetInfoType, ArtistSearchType, ArtistGetSimilarType, ArtistGetTopAlbumsType, ArtistGetTopTagsType, ArtistGetTopTracksType } from '../typings/index.js';
export default class Artist extends Base {

@@ -5,0 +5,0 @@ /**

@@ -1,2 +0,2 @@

import { convertImageSizes, convertURL } from '../utils/convert.js';
import { convertImageSizes, createLastFmURL } from '../utils/convert.js';
import Base from '../base.js';

@@ -12,7 +12,7 @@ export default class Artist extends Base {

method: 'artist.getInfo',
artist: params.artist,
username: params.username,
...params,
});
return {
name: artist.name,
mbid: artist.mbid,
description: artist.bio.summary,

@@ -25,3 +25,3 @@ onTour: Boolean(Number(artist.ontour)).valueOf(),

userStats: {
userPlayCount: (params.username && Number(artist.stats.userplaycount)) || null,
userPlayCount: Number(artist.stats.userplaycount),
},

@@ -37,5 +37,5 @@ url: artist.url,

async getSimilar(params) {
const { similarartists: { artist, '@attr': attr }, } = await this.sendRequest({
const { similarartists: { artist: artistMatches, '@attr': attr }, } = await this.sendRequest({
method: 'artist.getSimilar',
artist: params.artist,
...params,
limit: params.limit ?? 30,

@@ -47,8 +47,9 @@ });

name: attr.artist,
url: `https://www.last.fm/music/${convertURL(attr.artist)}`,
url: createLastFmURL('artist', attr.artist),
},
},
artists: artist.map((artist) => ({
artists: artistMatches.map((artist) => ({
match: Number(artist.match),
name: artist.name,
mbid: artist.mbid,
url: artist.url,

@@ -65,5 +66,5 @@ })),

async getTopAlbums(params) {
const { topalbums: { album, '@attr': attr }, } = await this.sendRequest({
const { topalbums: { album: albumMatches, '@attr': attr }, } = await this.sendRequest({
method: 'artist.getTopAlbums',
artist: params.artist,
...params,
limit: params.limit ?? 50,

@@ -76,3 +77,3 @@ page: params.page ?? 1,

name: attr.artist,
url: `https://www.last.fm/music/${convertURL(attr.artist)}`,
url: createLastFmURL('artist', attr.artist),
},

@@ -84,3 +85,3 @@ page: Number(attr.page),

},
albums: album.map((album) => ({
albums: albumMatches.map((album) => ({
name: album.name,

@@ -93,3 +94,3 @@ scrobbles: Number(album.playcount),

url: album.url,
image: convertImageSizes(album.image) || null,
image: convertImageSizes(album.image),
})),

@@ -103,5 +104,5 @@ };

async getTopTags(params) {
const { toptags: { tag, '@attr': attr }, } = await this.sendRequest({
const { toptags: { tag: tagMatches, '@attr': attr }, } = await this.sendRequest({
method: 'artist.getTopTags',
artist: params.artist,
...params,
});

@@ -111,5 +112,5 @@ return {

name: attr.artist,
url: `https://www.last.fm/music/${convertURL(attr.artist)}`,
url: createLastFmURL('artist', attr.artist),
},
tags: tag.map((tag) => ({
tags: tagMatches.map((tag) => ({
count: tag.count,

@@ -128,5 +129,5 @@ name: tag.name,

async getTopTracks(params) {
const { toptracks: { track, '@attr': attr }, } = await this.sendRequest({
const { toptracks: { track: trackMatches, '@attr': attr }, } = await this.sendRequest({
method: 'artist.getTopTracks',
artist: params.artist,
...params,
limit: params.limit ?? 50,

@@ -139,3 +140,3 @@ page: params.page ?? 1,

name: attr.artist,
url: `https://www.last.fm/music/${convertURL(attr.artist)}`,
url: createLastFmURL('artist', attr.artist),
},

@@ -147,5 +148,6 @@ page: Number(attr.page),

},
tracks: track.map((track) => ({
tracks: trackMatches.map((track) => ({
rank: Number(track['@attr'].rank),
name: track.name,
mbid: track.mbid,
artist: {

@@ -170,5 +172,5 @@ name: track.artist.name,

async search(params) {
const { results, results: { artistmatches: { artist }, }, } = await this.sendRequest({
const { results, results: { artistmatches: { artist: artistMatches }, }, } = await this.sendRequest({
method: 'artist.search',
artist: params.artist,
...params,
limit: params.limit ?? 30,

@@ -184,4 +186,5 @@ page: params.page ?? 1,

},
artists: artist.map((artist) => ({
artists: artistMatches.map((artist) => ({
name: artist.name,
mbid: artist.mbid,
listeners: Number(artist.listeners),

@@ -188,0 +191,0 @@ url: artist.url,

import Base from '../base.js';
import type { ChartGetTopArtistsType, ChartGetTopTagsType, ChartGetTopTracksType } from '../types/index.js';
import type { ChartGetTopArtistParams, ChartGetTopTagsParams, ChartGetTopTracksParams } from '../params/chart.params.js';
import type { ChartGetTopArtistsType, ChartGetTopTagsType, ChartGetTopTracksType } from '../typings/index.js';
export default class Chart extends Base {

@@ -5,0 +5,0 @@ /**

@@ -9,3 +9,3 @@ import Base from '../base.js';

async getTopArtists(params) {
const { artists: { artist, '@attr': attr }, } = await this.sendRequest({
const { artists: { artist: artistMatches, '@attr': attr }, } = await this.sendRequest({
method: 'chart.getTopArtists',

@@ -22,4 +22,5 @@ limit: params?.limit ?? 30,

},
artists: artist.map((artist) => ({
artists: artistMatches.map((artist) => ({
name: artist.name,
mbid: artist.mbid,
stats: {

@@ -39,3 +40,3 @@ scrobbles: Number(artist.playcount),

async getTopTags(params) {
const { tags: { tag, '@attr': attr }, } = await this.sendRequest({
const { tags: { tag: tagMatches, '@attr': attr }, } = await this.sendRequest({
method: 'chart.getTopTags',

@@ -52,3 +53,3 @@ limit: params?.limit ?? 30,

},
tags: tag.map((tag) => ({
tags: tagMatches.map((tag) => ({
name: tag.name,

@@ -69,3 +70,3 @@ stats: {

async getTopTracks(params) {
const { tracks: { track, '@attr': attr }, } = await this.sendRequest({
const { tracks: { track: trackMatches, '@attr': attr }, } = await this.sendRequest({
method: 'chart.getTopTracks',

@@ -82,13 +83,14 @@ limit: params?.limit ?? 30,

},
tracks: track.map((track) => ({
name: track.name,
tracks: trackMatches.map((tag) => ({
name: tag.name,
mbid: tag.mbid,
stats: {
scrobbles: Number(track.playcount),
listeners: Number(track.listeners),
scrobbles: Number(tag.playcount),
listeners: Number(tag.listeners),
},
artist: {
name: track.artist.name,
url: track.artist.url,
name: tag.artist.name,
url: tag.artist.url,
},
url: track.url,
url: tag.url,
})),

@@ -95,0 +97,0 @@ };

import Base from '../base.js';
import type { GeoGetTopArtistsType, GeoGetTopTracksType } from '../types/index.js';
import type { GeoGetTopArtistsParams, GeoGetTopTracksParams } from '../params/geo.params.js';
import type { GeoGetTopArtistsType, GeoGetTopTracksType } from '../typings/index.js';
export default class Geo extends Base {

@@ -5,0 +5,0 @@ /**

@@ -10,5 +10,5 @@ import Base from '../base.js';

async getTopArtists(params) {
const { topartists: { artist, '@attr': attr }, } = await this.sendRequest({
const { topartists: { artist: artistMatches, '@attr': attr }, } = await this.sendRequest({
method: 'geo.getTopArtists',
country: params.country,
...params,
limit: params.limit ?? 50,

@@ -25,4 +25,5 @@ page: params.page ?? 1,

},
artists: artist.map((artist) => ({
artists: artistMatches.map((artist) => ({
name: artist.name,
mbid: artist.mbid,
listeners: Number(artist.listeners),

@@ -40,5 +41,5 @@ url: artist.url,

async getTopTracks(params) {
const { tracks: { track, '@attr': attr }, } = await this.sendRequest({
const { tracks: { track: trackMatches, '@attr': attr }, } = await this.sendRequest({
method: 'geo.getTopTracks',
country: params.country,
...params,
limit: params.limit ?? 50,

@@ -55,9 +56,11 @@ page: params.page ?? 1,

},
tracks: track.map((track) => ({
tracks: trackMatches.map((track) => ({
rank: Number(track['@attr'].rank),
name: track.name,
duration: Number(track.duration) || null,
mbid: track.mbid,
duration: Number(track.duration),
listeners: Number(track.listeners),
artist: {
name: track.artist.name,
mbid: track.artist.mbid,
url: track.artist.url,

@@ -64,0 +67,0 @@ },

import Base from '../base.js';
import type { TagGetInfoType, TagGetTopAlbumsType, TagGetTopArtistsType, TagGetTopTracksType, TagGetWeeklyChartListType } from '../types/index.js';
import type { TagGetInfoParams, TagGetTopAlbumsParams, TagGetTopArtistsParams, TagGetTopTracksParams, TagGetWeeklyChartListParams } from '../params/tag.params.js';
import type { TagGetInfoParams, TagGetTopAlbumsParams, TagGetTopArtistsParams, TagGetTopTracksParams, TagGetWeeklyChartListParams } from '../params/index.js';
import type { TagGetInfoType, TagGetTopAlbumsType, TagGetTopArtistsType, TagGetTopTracksType, TagGetWeeklyChartListType } from '../typings/index.js';
export default class Tag extends Base {

@@ -5,0 +5,0 @@ /**

@@ -1,2 +0,2 @@

import { convertImageSizes, convertURL } from '../utils/convert.js';
import { convertImageSizes, createLastFmURL } from '../utils/convert.js';
import Base from '../base.js';

@@ -20,3 +20,3 @@ export default class Tag extends Base {

},
url: `https://www.last.fm/tag/${convertURL(tag.name)}`,
url: createLastFmURL('tag', tag.name),
};

@@ -31,5 +31,5 @@ }

async getTopAlbums(params) {
const { albums: { album, '@attr': attr }, } = await this.sendRequest({
const { albums: { album: albumMatches, '@attr': attr }, } = await this.sendRequest({
method: 'tag.getTopAlbums',
tag: params.tag,
...params,
limit: params.limit ?? 50,

@@ -46,11 +46,13 @@ page: params.page ?? 1,

},
albums: album.map((album) => ({
albums: albumMatches.map((album) => ({
rank: Number(album['@attr'].rank),
name: album.name,
mbid: album.mbid,
artist: {
name: album.artist.name,
mbid: album.artist.mbid,
url: album.artist.url,
},
url: `https://www.last.fm/music/${convertURL(album.artist.name)}/${convertURL(album.name)}`,
image: convertImageSizes(album.image) || null,
url: createLastFmURL('album', album.artist.name, album.name),
image: convertImageSizes(album.image),
})),

@@ -66,5 +68,5 @@ };

async getTopArtists(params) {
const { topartists: { artist, '@attr': attr }, } = await this.sendRequest({
const { topartists: { artist: artistMatches, '@attr': attr }, } = await this.sendRequest({
method: 'tag.getTopArtists',
tag: params.tag,
...params,
limit: params.limit ?? 50,

@@ -81,5 +83,6 @@ page: params.page ?? 1,

},
artists: artist.map((artist) => ({
artists: artistMatches.map((artist) => ({
rank: Number(artist['@attr'].rank),
name: artist.name,
mbid: artist.mbid,
url: artist.url,

@@ -96,5 +99,5 @@ })),

async getTopTracks(params) {
const { tracks: { track, '@attr': attr }, } = await this.sendRequest({
const { tracks: { track: trackMatches, '@attr': attr }, } = await this.sendRequest({
method: 'tag.getTopTracks',
tag: params.tag,
...params,
limit: params.limit ?? 50,

@@ -111,8 +114,10 @@ page: params.page ?? 1,

},
tracks: track.map((track) => ({
tracks: trackMatches.map((track) => ({
rank: Number(track['@attr'].rank),
name: track.name,
duration: Number(track.duration) || null,
mbid: track.mbid,
duration: Number(track.duration),
artist: {
name: track.artist.name,
mbid: track.artist.mbid,
url: track.artist.url,

@@ -129,5 +134,5 @@ },

async getWeeklyChartList(params) {
const { weeklychartlist: { chart, '@attr': attr }, } = await this.sendRequest({
const { weeklychartlist: { chart: chartMatches, '@attr': attr }, } = await this.sendRequest({
method: 'tag.getWeeklyChartList',
tag: params.tag,
...params,
});

@@ -138,3 +143,3 @@ return {

},
positions: chart.map((chart) => ({
positions: chartMatches.map((chart) => ({
from: new Date(Number(chart.from) * 1000),

@@ -141,0 +146,0 @@ to: new Date(Number(chart.to) * 1000),

import Base from '../base.js';
import type { TrackGetInfoType, TrackGetSimilarType, TrackGetTopTagsType, TrackSearchType } from '../types/index.js';
import type { TrackGetInfoParams, TrackGetSimilarParams, TrackGetTopTagsParams, TrackSearchParams } from '../params/track.params.js';
import type { TrackGetInfoParams, TrackGetSimilarParams, TrackGetTopTagsParams, TrackSearchParams } from '../params/index.js';
import type { TrackGetInfoType, TrackGetSimilarType, TrackGetTopTagsType, TrackSearchType } from '../typings/index.js';
export default class Track extends Base {

@@ -24,3 +24,3 @@ /**

*/
getTopTags(parmas: TrackGetTopTagsParams): Promise<TrackGetTopTagsType>;
getTopTags(params: TrackGetTopTagsParams): Promise<TrackGetTopTagsType>;
/**

@@ -27,0 +27,0 @@ * Search for a track by name.

@@ -1,2 +0,2 @@

import { convertImageSizes, convertURL } from '../utils/convert.js';
import { convertImageSizes, createLastFmURL } from '../utils/convert.js';
import Base from '../base.js';

@@ -11,11 +11,10 @@ export default class Track extends Base {

async getInfo(params) {
const { track, track: { album, toptags: { tag }, }, } = await this.sendRequest({
const { track, track: { album, toptags: { tag: tagMatches }, }, } = await this.sendRequest({
method: 'track.getInfo',
artist: params.artist,
track: params.track,
username: params.username,
...params,
});
return {
name: track.name,
duration: Number(track.duration) || null,
mbid: track.mbid,
duration: Number(track.duration),
stats: {

@@ -26,16 +25,18 @@ scrobbles: Number(track.playcount),

userStats: {
userLoved: (params.username && Boolean(Number(track.userloved)).valueOf()) || null,
userPlayCount: (params.username && Number(track.userplaycount)) || null,
userLoved: Boolean(Number(track.userloved)).valueOf(),
userPlayCount: Number(track.userplaycount),
},
artist: {
name: track.artist.name,
mbid: track.artist.mbid,
url: track.artist.url,
},
album: {
position: Number(album?.['@attr']?.position) || null,
name: album?.title || null,
image: convertImageSizes(album?.image || null) || null,
url: album?.url || null,
position: Number(album?.['@attr']?.position),
name: album?.title,
mbid: album?.mbid,
image: convertImageSizes(album?.image),
url: album?.url,
},
tags: tag.map((tag) => ({
tags: tagMatches.map((tag) => ({
name: tag.name,

@@ -54,6 +55,5 @@ url: tag.url,

async getSimilar(params) {
const { similartracks: { track, '@attr': attr }, } = await this.sendRequest({
const { similartracks: { track: trackMatches, '@attr': attr }, } = await this.sendRequest({
method: 'track.getSimilar',
artist: params.artist,
track: params.track,
...params,
limit: params.limit ?? 30,

@@ -65,9 +65,9 @@ });

name: attr.artist,
url: `https://www.last.fm/music/${convertURL(attr.artist)}`,
url: createLastFmURL('artist', attr.artist),
},
url: `https://www.last.fm/music/${convertURL(attr.artist)}/_/${convertURL(params.track)}`,
tracks: track.map((track) => ({
url: createLastFmURL('track', attr.artist, params.track),
tracks: trackMatches.map((track) => ({
match: Number(track.match),
name: track.name,
duration: Number(track.duration) || null,
duration: Number(track.duration),
scrobbles: Number(track.playcount),

@@ -79,3 +79,3 @@ artist: {

url: track.url,
image: convertImageSizes(track.image) || null,
image: convertImageSizes(track.image),
})),

@@ -89,7 +89,6 @@ };

*/
async getTopTags(parmas) {
const { toptags: { tag, '@attr': attr }, } = await this.sendRequest({
async getTopTags(params) {
const { toptags: { tag: tagMatches, '@attr': attr }, } = await this.sendRequest({
method: 'track.getTopTags',
artist: parmas.artist,
track: parmas.track,
...params,
});

@@ -100,6 +99,6 @@ return {

name: attr.artist,
url: `https://www.last.fm/music/${convertURL(attr.artist)}`,
url: createLastFmURL('artist', attr.artist),
},
url: `https://www.last.fm/music/${convertURL(attr.artist)}/_/${convertURL(attr.track)}`,
tags: tag.map((tag) => ({
url: createLastFmURL('track', attr.artist, attr.track),
tags: tagMatches.map((tag) => ({
count: Number(tag.count),

@@ -118,5 +117,5 @@ name: tag.name,

async search(params) {
const { results, results: { trackmatches: { track }, }, } = await this.sendRequest({
const { results, results: { trackmatches: { track: trackMatches }, }, } = await this.sendRequest({
method: 'track.search',
track: params.track,
...params,
limit: params.limit ?? 30,

@@ -132,8 +131,9 @@ page: params.page ?? 1,

},
tracks: track.map((track) => ({
tracks: trackMatches.map((track) => ({
name: track.name,
mbid: track.mbid,
listeners: Number(track.listeners),
artist: {
name: track.artist,
url: `https://www.last.fm/music/${convertURL(track.artist)}`,
url: createLastFmURL('artist', track.artist),
},

@@ -140,0 +140,0 @@ url: track.url,

import Base from '../base.js';
import type { UserGetInfoType, UserGetLovedTracksType, UserGetPersonalTagsType, UserGetRecentTracksType, UserGetTopAlbumsType, UserGetTopArtistsType, UserGetTopTagsType, UserGetTopTracksType, UserGetFriendsType } from '../types/index.js';
import type { UserGetFriendsParams, UserGetInfoParams, UserGetLovedTracksParams, UserGetPersonalTagsParams, UserGetRecentTracksParams, UserGetTopAlbumsParams, UserGetTopArtistsParams, UserGetTopTagsParams, UserGetTopTracksParams } from '../params/user.params.js';
import type { UserGetFriendsParams, UserGetInfoParams, UserGetLovedTracksParams, UserGetPersonalTagsParams, UserGetRecentTracksParams, UserGetTopAlbumsParams, UserGetTopArtistsParams, UserGetTopTagsParams, UserGetTopTracksParams } from '../params/index.js';
import type { UserGetInfoType, UserGetLovedTracksType, UserGetPersonalTagsType, UserGetRecentTracksType, UserGetTopAlbumsType, UserGetTopArtistsType, UserGetTopTagsType, UserGetTopTracksType, UserGetFriendsType } from '../typings/index.js';
export default class User extends Base {
/**
* Returns information about a user's profile.
* @param username - The name of the user.
* */
getInfo(params: UserGetInfoParams): Promise<UserGetInfoType>;
/**
* Returns a list of the user's friends.

@@ -18,2 +13,7 @@ * @param username - The name of the user.

/**
* Returns information about a user's profile.
* @param username - The name of the user.
* */
getInfo(params: UserGetInfoParams): Promise<UserGetInfoType>;
/**
* Returns the loved tracks as set by the user.

@@ -20,0 +20,0 @@ * @param username - The name of the user.

@@ -1,23 +0,5 @@

import { convertImageSizes, convertURL } from '../utils/convert.js';
import { convertImageSizes, createLastFmURL } from '../utils/convert.js';
import Base from '../base.js';
export default class User extends Base {
/**
* Returns information about a user's profile.
* @param username - The name of the user.
* */
async getInfo(params) {
const { user } = await this.sendRequest({
method: 'user.getInfo',
user: params.username,
});
return {
name: user.name,
realName: user.realname || null,
country: user.country,
registered: new Date(user.registered['#text'] * 1000),
url: user.url,
image: convertImageSizes(user.image) || null,
};
}
/**
* Returns a list of the user's friends.

@@ -29,5 +11,5 @@ * @param username - The name of the user.

async getFriends(params) {
const { friends: { user, '@attr': attr }, } = await this.sendRequest({
const { friends: { user: userMatches, '@attr': attr }, } = await this.sendRequest({
method: 'user.getFriends',
user: params.username,
...params,
limit: params.limit ?? 50,

@@ -44,9 +26,9 @@ page: params.page ?? 1,

},
friends: user.map((user) => ({
friends: userMatches.map((user) => ({
name: user.name,
realName: user.realname || null,
country: user.country,
realName: user.realname === '' ? undefined : user.realname,
country: user.country === 'None' ? undefined : user.country,
registered: new Date(Number(user.registered.unixtime) * 1000),
url: user.url,
image: convertImageSizes(user.image) || null,
image: convertImageSizes(user.image),
})),

@@ -56,2 +38,26 @@ };

/**
* Returns information about a user's profile.
* @param username - The name of the user.
* */
async getInfo(params) {
const { user } = await this.sendRequest({
method: 'user.getInfo',
...params,
});
return {
name: user.name,
realName: user.realname === '' ? undefined : user.realname,
country: user.country === 'None' ? undefined : user.country,
registered: new Date(user.registered['#text'] * 1000),
stats: {
albumCount: Number(user.album_count),
artistCount: Number(user.artist_count),
playCount: Number(user.playcount),
trackCount: Number(user.track_count),
},
url: user.url,
image: convertImageSizes(user.image),
};
}
/**
* Returns the loved tracks as set by the user.

@@ -63,5 +69,5 @@ * @param username - The name of the user.

async getLovedTracks(params) {
const { lovedtracks: { track, '@attr': attr }, } = await this.sendRequest({
const { lovedtracks: { track: trackMatches, '@attr': attr }, } = await this.sendRequest({
method: 'user.getLovedTracks',
user: params.username,
...params,
limit: params.limit ?? 50,

@@ -78,7 +84,9 @@ page: params.page ?? 1,

},
tracks: track.map((track) => ({
tracks: trackMatches.map((track) => ({
name: track.name,
mbid: track.mbid,
date: new Date(Number(track.date.uts) * 1000),
artist: {
name: track.artist.name,
mbid: track.artist.mbid,
url: track.artist.url,

@@ -99,5 +107,3 @@ },

method: 'user.getPersonalTags',
user: params.username,
tag: params.tag,
taggingtype: params.tagType,
...params,
});

@@ -112,17 +118,16 @@ const responseTypes = {

url: album.url,
})) || null,
})),
artist: artists?.artist.map((artist) => ({
name: artist.name,
url: artist.url,
})) || null,
})),
track: tracks?.track.map((track) => ({
name: track.name,
artist: {
name: typeof track.artist === 'string' ? track.artist : track.artist.name,
url: typeof track.artist === 'string' ? track.artist : track.artist.url,
name: track.artist.name,
url: track.artist.url,
},
url: track.url,
})) || null,
})),
};
const response = responseTypes[params.tagType] || null;
return {

@@ -137,3 +142,3 @@ search: {

},
response,
response: responseTypes[params.taggingtype] || undefined,
};

@@ -148,5 +153,5 @@ }

async getRecentTracks(params) {
const { recenttracks: { track, '@attr': attr }, } = await this.sendRequest({
const { recenttracks: { track: trackMatches, '@attr': attr }, } = await this.sendRequest({
method: 'user.getRecentTracks',
user: params.username,
...params,
limit: params.limit ?? 50,

@@ -158,3 +163,3 @@ page: params.page ?? 1,

user: attr.user,
nowPlaying: track[0]['@attr']?.nowplaying === 'true',
nowPlaying: trackMatches[0]['@attr']?.nowplaying === 'true',
page: Number(attr.page),

@@ -165,11 +170,16 @@ itemsPerPage: Number(attr.perPage),

},
tracks: track.map((track) => ({
tracks: trackMatches.map((track) => ({
dateAdded: new Date(Number(track.date.uts) * 1000),
name: track.name,
mbid: track.mbid === '' ? undefined : track.mbid,
artist: {
name: track.artist['#text'],
url: `https://www.last.fm/music/${convertURL(track.artist['#text'])}`,
url: createLastFmURL('artist', track.artist['#text']),
},
album: track.album['#text'] || null,
album: {
name: track.album['#text'],
mbid: track.album.mbid,
},
url: track.url,
image: convertImageSizes(track.image) || null,
image: convertImageSizes(track.image),
})),

@@ -185,5 +195,5 @@ };

async getTopAlbums(params) {
const { topalbums: { album, '@attr': attr }, } = await this.sendRequest({
const { topalbums: { album: albumMatches, '@attr': attr }, } = await this.sendRequest({
method: 'user.getTopAlbums',
user: params.username,
...params,
limit: params.limit ?? 50,

@@ -200,12 +210,14 @@ page: params.page ?? 1,

},
albums: album.map((album) => ({
albums: albumMatches.map((album) => ({
rank: Number(album['@attr'].rank),
name: album.name,
mbid: album.mbid,
playCount: Number(album.playcount),
artist: {
name: album.artist.name,
mbid: album.artist.mbid,
url: album.artist.url,
},
url: album.url,
image: convertImageSizes(album.image) || null,
image: convertImageSizes(album.image),
})),

@@ -221,5 +233,5 @@ };

async getTopArtists(params) {
const { topartists: { artist, '@attr': attr }, } = await this.sendRequest({
const { topartists: { artist: artistMatches, '@attr': attr }, } = await this.sendRequest({
method: 'user.getTopArtists',
user: params.username,
...params,
limit: params.limit ?? 50,

@@ -236,5 +248,6 @@ page: params.page ?? 1,

},
artists: artist.map((artist) => ({
artists: artistMatches.map((artist) => ({
rank: Number(artist['@attr'].rank),
name: artist.name,
mbid: artist.mbid,
scrobbles: Number(artist.playcount),

@@ -251,5 +264,5 @@ url: artist.url,

async getTopTags(params) {
const { toptags: { tag, '@attr': attr }, } = await this.sendRequest({
const { toptags: { tag: tagMatches, '@attr': attr }, } = await this.sendRequest({
method: 'user.getTopTags',
user: params.username,
...params,
limit: params.limit ?? 50,

@@ -261,3 +274,3 @@ });

},
tags: tag.map((tag) => ({
tags: tagMatches.map((tag) => ({
count: Number(tag.count),

@@ -276,5 +289,5 @@ name: tag.name,

async getTopTracks(params) {
const { toptracks: { track, '@attr': attr }, } = await this.sendRequest({
const { toptracks: { track: trackMatches, '@attr': attr }, } = await this.sendRequest({
method: 'user.getTopTracks',
user: params.username,
...params,
limit: params.limit ?? 50,

@@ -291,7 +304,8 @@ page: params.page ?? 1,

},
tracks: track.map((track) => ({
tracks: trackMatches.map((track) => ({
rank: Number(track['@attr'].rank),
name: track.name,
mbid: track.mbid,
stats: {
duration: Number(track.duration) || null,
duration: Number(track.duration),
userPlayCount: Number(track.playcount),

@@ -301,6 +315,7 @@ },

name: track.artist.name,
mbid: track.artist.mbid,
url: track.artist.url,
},
url: track.url,
image: convertImageSizes(track.image) || null,
image: convertImageSizes(track.image),
})),

@@ -307,0 +322,0 @@ };

@@ -8,3 +8,2 @@ import Album from './classes/album.class.js';

import User from './classes/user.class.js';
export * from './types/index.js';
export default class SimpleFMClient {

@@ -22,2 +21,3 @@ private readonly key;

});
private validateApiKey;
}

@@ -9,3 +9,3 @@ import Album from './classes/album.class.js';

import LastFMError from './utils/error.js';
export * from './types/index.js';
import { pkg } from './utils/package.js';
export default class SimpleFMClient {

@@ -22,8 +22,4 @@ key;

this.key = key;
if (!key)
throw new LastFMError({
message: 'You have not specified a Last.fm API key. Get one here: https://www.last.fm/api/account/create',
error: 6,
});
options.userAgent ??= `simple-fm - a simple Last.fm wrapper written in TypeScript (GitHub: https://github.com/solelychloe/simple-fm)`;
this.validateApiKey();
options.userAgent ??= `simple-fm v${pkg.version} - a simple Last.fm wrapper written in TypeScript (https://github.com/solelychloe/simple-fm)`;
this.album = new Album(key, options.userAgent);

@@ -37,2 +33,9 @@ this.artist = new Artist(key, options.userAgent);

}
validateApiKey() {
if (!this.key)
throw new LastFMError({
message: 'A Last.fm API key is required. Get one here: https://www.last.fm/api/account/create',
error: 6,
});
}
}

@@ -17,3 +17,3 @@ export interface UserGetInfoParams {

tag: string;
tagType: 'album' | 'artist' | 'track';
taggingtype: 'album' | 'artist' | 'track';
}

@@ -20,0 +20,0 @@ export interface UserGetRecentTracksParams {

@@ -1,2 +0,2 @@

import { RequestMethod } from './types/index.js';
import type { RequestMethod } from './typings/index.js';
export interface LastFMArgument {

@@ -13,2 +13,5 @@ method: RequestMethod;

username?: string;
sk?: string;
token?: string;
api_sig?: string;
page?: number;

@@ -26,3 +29,6 @@ limit?: number;

constructor(key: string, userAgent: string, params: LastFMArgument);
get<T = unknown>(): Promise<T>;
private isPostRequest;
private post;
private get;
execute(): Promise<unknown>;
}

@@ -12,2 +12,9 @@ import { $fetch, FetchError } from 'ofetch';

}
// TODO: Implement post methods.
isPostRequest() {
return Object.hasOwn(this.params, 'sk');
}
post() {
throw new Error('Method not implemented yet.');
}
async get() {

@@ -20,15 +27,28 @@ const baseURL = 'https://ws.audioscrobbler.com/2.0';

};
const data = await $fetch(baseURL, {
params,
headers: {
'User-Agent': this.userAgent,
},
}).catch((err) => {
if (err instanceof FetchError && !err.response?.ok)
throw new LastFMError(err.data);
});
if (data.error === 6)
throw new LastFMError(data);
return data;
try {
const data = await $fetch(baseURL, {
params,
headers: {
'User-Agent': this.userAgent,
},
});
if (data.error === 6)
throw new LastFMError(data);
return data;
}
catch (err) {
if (err instanceof FetchError)
throw new FetchError(err.message);
else if (err instanceof LastFMError)
throw new LastFMError(err.response);
else
console.error(err);
}
}
execute() {
if (this.isPostRequest())
return this.post();
else
return this.get();
}
}

@@ -1,7 +0,6 @@

import type { Album, Artist, Image, OpenSearchMeta, Tag, Track } from '../index.js';
type ObjArray<T> = T | T[];
import type { AlbumResponse, ArtistResponse, ImageResponse, ObjectArray, OpenSearchResponse, TagResponse, TrackResponse } from './index.js';
export declare interface AlbumGetInfoResponse {
album: Album & {
album: AlbumResponse & {
tags: {
tag: Array<Tag & {
tag: Array<TagResponse & {
url: string;

@@ -15,3 +14,3 @@ }>;

tracks: {
track: ObjArray<Track & {
track: ObjectArray<TrackResponse & {
duration: string;

@@ -21,7 +20,7 @@ '@attr': {

};
artist: Artist;
artist: ArtistResponse;
}>;
};
url: string;
image: Image[] | null;
image?: ImageResponse[];
};

@@ -31,3 +30,3 @@ }

toptags: {
tag: Array<Tag & {
tag: Array<TagResponse & {
count: number;

@@ -43,3 +42,3 @@ url: string;

export declare interface AlbumSearchResponse {
results: OpenSearchMeta & {
results: OpenSearchResponse & {
'opensearch:Query': {

@@ -49,3 +48,3 @@ searchTerms: string;

albummatches: {
album: Array<Album & {
album: Array<AlbumResponse & {
artist: string;

@@ -56,2 +55,1 @@ }>;

}
export {};

@@ -1,4 +0,5 @@

import type { Album, Artist, AttrMeta, OpenSearchMeta, Track, Tag } from '../index.js';
import type { AlbumResponse, ArtistResponse, AttrResponse, OpenSearchResponse, TagResponse, TrackResponse } from './index.js';
export declare interface ArtistGetInfoResponse {
artist: Artist & {
artist: ArtistResponse & {
mbid: string;
stats: {

@@ -17,3 +18,4 @@ listeners: string;

similarartists: {
artist: Array<Artist & {
artist: Array<ArtistResponse & {
mbid: string;
match: string;

@@ -28,7 +30,7 @@ }>;

topalbums: {
album: Array<Album & {
album: Array<AlbumResponse & {
playcount: number;
artist: Artist;
artist: ArtistResponse;
}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
artist: string;

@@ -40,3 +42,3 @@ };

toptags: {
tag: Array<Tag & {
tag: Array<TagResponse & {
url: string;

@@ -52,6 +54,6 @@ count: number;

toptracks: {
track: Array<Track & {
track: Array<TrackResponse & {
listeners: string;
playcount: string;
artist: Artist;
artist: ArtistResponse;
'@attr': {

@@ -61,3 +63,3 @@ rank: string;

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
artist: string;

@@ -68,3 +70,3 @@ };

export declare interface ArtistSearchResponse {
results: OpenSearchMeta & {
results: OpenSearchResponse & {
'opensearch:Query': {

@@ -74,3 +76,4 @@ searchTerms: string;

artistmatches: {
artist: Array<Artist & {
artist: Array<ArtistResponse & {
mbid: string;
listeners: string;

@@ -77,0 +80,0 @@ }>;

@@ -1,9 +0,10 @@

import type { Artist, AttrMeta, Track, Tag } from '../index.js';
import type { ArtistResponse, AttrResponse, TagResponse, TrackResponse } from './index.js';
export declare interface ChartGetTopArtistsResponse {
artists: {
artist: Array<Artist & {
artist: Array<ArtistResponse & {
mbid: string;
playcount: string;
listeners: string;
}>;
'@attr': AttrMeta;
'@attr': AttrResponse;
};

@@ -13,7 +14,7 @@ }

tags: {
tag: Array<Tag & {
tag: Array<TagResponse & {
taggings: string;
url: string;
}>;
'@attr': AttrMeta;
'@attr': AttrResponse;
};

@@ -23,9 +24,11 @@ }

tracks: {
track: Array<Track & {
track: Array<TrackResponse & {
playcount: string;
listeners: string;
artist: Artist;
artist: ArtistResponse & {
mbid: string;
};
}>;
'@attr': AttrMeta;
'@attr': AttrResponse;
};
}

@@ -1,8 +0,9 @@

import type { Artist, AttrMeta, Track } from '../index.js';
import type { ArtistResponse, AttrResponse, TrackResponse } from './index.js';
export declare interface GeoGetTopArtistsResponse {
topartists: {
artist: Array<Artist & {
artist: Array<ArtistResponse & {
mbid: string;
listeners: string;
}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
country: string;

@@ -14,6 +15,8 @@ };

tracks: {
track: Array<Track & {
track: Array<TrackResponse & {
duration: string;
listeners: string;
artist: Artist;
artist: ArtistResponse & {
mbid: string;
};
'@attr': {

@@ -23,3 +26,3 @@ rank: string;

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
country: string;

@@ -26,0 +29,0 @@ };

@@ -1,8 +0,58 @@

import type { Track } from '../index.js';
export declare interface TrackResponse extends Track {
duration: string;
'@attr': {
rank: number;
export type ObjectArray<T> = T | T[];
export interface AttrResponse {
page: string;
perPage: string;
totalPages: string;
total: string;
}
export interface OpenSearchResponse {
'opensearch:Query': {
startPage: string;
};
'opensearch:totalResults': string;
'opensearch:itemsPerPage': string;
}
export interface ImageResponse {
size: string;
'#text': string;
}
export interface Registered {
'#text': number;
unixtime: string;
}
export interface AlbumResponse {
name: string;
mbid?: string;
artist: ArtistResponse | string;
url: string;
image: ImageResponse[];
}
export interface ArtistResponse {
name: string;
mbid?: string;
url: string;
image?: ImageResponse[];
}
export interface TagResponse {
name: string;
url?: string;
count?: number;
total?: number;
reach?: number;
}
export interface TrackResponse {
name: string;
mbid: string;
artist: ArtistResponse | string;
url: string;
image: ImageResponse[];
}
export interface UserResponse {
name: string;
realname?: string;
country?: string;
registered: Registered;
url: string;
image?: ImageResponse[];
}
export * from './album.response.js';

@@ -9,0 +59,0 @@ export * from './artist.response.js';

@@ -1,4 +0,4 @@

import type { Album, Artist, AttrMeta, Track, Tag } from '../index.js';
import type { AlbumResponse, ArtistResponse, AttrResponse, TagResponse, TrackResponse } from './index.js';
export declare interface TagGetInfoResponse {
tag: Tag & {
tag: TagResponse & {
total: number;

@@ -13,4 +13,6 @@ wiki: {

albums: {
album: Array<Album & {
artist: Artist;
album: Array<AlbumResponse & {
artist: ArtistResponse & {
mbid: string;
};
'@attr': {

@@ -20,3 +22,3 @@ rank: number;

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
tag: string;

@@ -28,3 +30,4 @@ };

topartists: {
artist: Array<Artist & {
artist: Array<ArtistResponse & {
mbid: string;
'@attr': {

@@ -34,3 +37,3 @@ rank: number;

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
tag: string;

@@ -42,5 +45,7 @@ };

tracks: {
track: Array<Track & {
track: Array<TrackResponse & {
duration: string;
artist: Artist;
artist: ArtistResponse & {
mbid: string;
};
'@attr': {

@@ -50,3 +55,3 @@ rank: string;

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
tag: string;

@@ -53,0 +58,0 @@ };

@@ -1,14 +0,11 @@

import type { Artist, Album, OpenSearchMeta, Tag, Track } from '../index.js';
import type { ArtistResponse, AlbumResponse, OpenSearchResponse, TagResponse, TrackResponse } from './index.js';
export declare interface TrackGetInfoResponse {
track: Track & {
track: TrackResponse & {
duration: string;
listeners: string;
playcount: string;
artist: Artist;
toptags: {
tag: Array<Tag & {
url: string;
}>;
artist: ArtistResponse & {
mbid: string;
};
album?: Album & {
album?: AlbumResponse & {
title: string;

@@ -19,2 +16,7 @@ '@attr'?: {

};
toptags: {
tag: Array<TagResponse & {
url: string;
}>;
};
userplaycount?: string;

@@ -26,7 +28,9 @@ userloved?: string;

similartracks: {
track: Array<Track & {
track: Array<TrackResponse & {
playcount: number;
match: number;
duration: number;
artist: Artist;
artist: ArtistResponse & {
mbid: string;
};
}>;

@@ -40,3 +44,3 @@ '@attr': {

toptags: {
tag: Array<Tag & {
tag: Array<TagResponse & {
count: number;

@@ -52,5 +56,5 @@ url: string;

export declare interface TrackSearchResponse {
results: OpenSearchMeta & {
results: OpenSearchResponse & {
trackmatches: {
track: Array<Track & {
track: Array<TrackResponse & {
artist: string;

@@ -57,0 +61,0 @@ listeners: string;

@@ -1,9 +0,6 @@

import type { Album, Artist, AttrMeta, Image, Tag, Track, User } from '../index.js';
export declare interface UserGetInfoResponse {
user: User;
}
import type { ArtistResponse, AlbumResponse, AttrResponse, ImageResponse, TagResponse, TrackResponse, UserResponse } from './index.js';
export declare interface UserGetFriendsResponse {
friends: {
user: User[];
'@attr': AttrMeta & {
user: UserResponse[];
'@attr': AttrResponse & {
user: string;

@@ -13,6 +10,16 @@ };

}
export declare interface UserGetInfoResponse {
user: UserResponse & {
album_count: string;
artist_count: string;
playcount: string;
track_count: string;
};
}
export declare interface UserGetLovedTracksResponse {
lovedtracks: {
track: Array<Track & {
artist: Artist;
track: Array<TrackResponse & {
artist: ArtistResponse & {
mbid: string;
};
date: {

@@ -23,3 +30,3 @@ uts: string;

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
user: string;

@@ -34,14 +41,22 @@ };

name: string;
artist: Artist;
artist: ArtistResponse & {
mbid: string;
};
url: string;
image: Image[];
image: ImageResponse[];
}>;
};
artists?: {
artist: Artist[];
artist: Array<ArtistResponse & {
mbid: string;
}>;
};
tracks?: {
track: Track[];
track: Array<TrackResponse & {
artist: ArtistResponse & {
mbid: string;
};
}>;
};
'@attr': AttrMeta & {
'@attr': AttrResponse & {
user: string;

@@ -54,9 +69,15 @@ tag: string;

recenttracks: {
track: Array<Track & {
track: Array<TrackResponse & {
artist: {
mbid: string;
'#text': string;
};
album: {
mbid: string;
'#text': string;
};
date: {
uts: string;
'#text': string;
};
'@attr'?: {

@@ -66,3 +87,3 @@ nowplaying: string;

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
user: string;

@@ -74,4 +95,6 @@ };

topalbums: {
album: Array<Album & {
artist: Artist;
album: Array<AlbumResponse & {
artist: ArtistResponse & {
mbid: string;
};
playcount: string;

@@ -82,3 +105,3 @@ '@attr': {

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
user: string;

@@ -90,3 +113,4 @@ };

topartists: {
artist: Array<Artist & {
artist: Array<ArtistResponse & {
mbid: string;
playcount: string;

@@ -97,3 +121,3 @@ '@attr': {

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
user: string;

@@ -105,3 +129,3 @@ };

toptags: {
tag: Array<Tag & {
tag: Array<TagResponse & {
count: number;

@@ -117,5 +141,7 @@ url: string;

toptracks: {
track: Array<Track & {
track: Array<TrackResponse & {
duration: string;
artist: Artist;
artist: ArtistResponse & {
mbid: string;
};
'@attr': {

@@ -126,3 +152,3 @@ rank: string;

}>;
'@attr': AttrMeta & {
'@attr': AttrResponse & {
user: string;

@@ -129,0 +155,0 @@ };

@@ -1,3 +0,6 @@

import type { Image, ImageType } from '../index.js';
export declare const convertImageSizes: (image: Image[] | null) => ImageType[] | null | undefined;
export declare const convertURL: (url: string) => string;
import type { ImageResponse } from '../responses/index.js';
import type { ImageType } from '../typings/index.js';
export declare const convertImageSizes: (images?: ImageResponse[]) => ImageType[] | undefined;
type LastFmURLType = 'album' | 'artist' | 'tag' | 'track';
export declare const createLastFmURL: <T extends LastFmURLType>(type: T, value: string, track?: (T extends "track" | "album" ? string : never) | undefined) => string | undefined;
export {};
const ImageSize = ['extralarge', 'large', 'medium', 'small'];
export const convertImageSizes = (image) => {
try {
const data = image
?.filter((i) => ImageSize.includes(i.size))
?.map((i) => ({
size: i.size,
url: i['#text'],
}));
return data;
export const convertImageSizes = (images) => {
if (!images)
return undefined;
const data = images
.filter((image) => image['#text'] && ImageSize.includes(image.size))
.map((image) => ({
size: image.size,
url: image['#text'],
}));
return data;
};
const convertURL = (url) => encodeURIComponent(url ?? '').replaceAll(/%20/g, '+');
export const createLastFmURL = (type, value, track) => {
switch (type) {
case 'album':
case 'track':
return `https://www.last.fm/music/${convertURL(value)}/_/${convertURL(track)}`;
case 'artist':
return `https://www.last.fm/music/${convertURL(value)}`;
case 'tag':
return `https://www.last.fm/tag/${convertURL(value)}`;
default:
return undefined;
}
catch (_) {
return null;
}
};
export const convertURL = (url) => {
return encodeURIComponent(url).replaceAll('%20', '+');
};
{
"name": "@solely/simple-fm",
"version": "1.5.3",
"version": "1.6.0",
"license": "Zlib",
"author": "Chloe Arciniega <solely@riseup.net> (https://arciniega.one)",
"description": "A simple, asynchronous Last.fm wrapper in TypeScript.",
"type": "module",
"author": "Chloe Arciniega <solely@riseup.net>",
"description": "A simple, asynchronous Last.fm wrapper in TypeScript.",
"main": "./dist/index.js",

@@ -12,10 +12,8 @@ "files": [

],
"scripts": {
"build": "tsc && tsconfig-replace-paths -p tsconfig.json -s src/",
"dev": "tsc --watch",
"lint": "eslint .",
"prepare": "yarn pack && tar -xvf package.tgz && rimraf ./package.tgz",
"prepack": "rimraf ./dist && yarn build",
"test": "vitest"
"publishConfig": {
"access": "public"
},
"engines": {
"node": ">=20"
},
"exports": {

@@ -25,3 +23,7 @@ ".": "./dist/index.js",

},
"repository": "https://github.com/solelychloe/simple-fm",
"homepage": "https://github.com/solelychloe/simple-fm#README",
"repository": {
"type": "git",
"url": "https://github.com/solelychloe/simple-fm.git"
},
"keywords": [

@@ -35,3 +37,6 @@ "lastfm",

],
"packageManager": "yarn@3.6.1",
"funding": {
"type": "individual",
"url": "https://ko-fi.com/solelychloe"
},
"dependencies": {

@@ -41,11 +46,12 @@ "ofetch": "^1.1.1"

"devDependencies": {
"@types/node": "^20.4.0",
"@typescript-eslint/eslint-plugin": "^5.61.0",
"@typescript-eslint/parser": "^5.61.0",
"@changesets/cli": "^2.26.2",
"@types/node": "^20.4.5",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"dotenv": "^16.3.1",
"eslint": "^8.44.0",
"eslint-config-clarity": "^1.0.3",
"eslint": "^8.46.0",
"eslint-config-clarity": "^1.0.6",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-import": "^2.28.0",
"eslint-plugin-prettier": "^5.0.0",
"prettier": "^3.0.0",

@@ -56,7 +62,18 @@ "rimraf": "^5.0.1",

"typescript": "^5.1.6",
"vite": "^4.4.0",
"vite": "^4.4.8",
"vite-tsconfig-paths": "^4.2.0",
"vitest": "^0.33.0",
"vitest": "^0.34.1",
"zod": "^3.21.4"
},
"scripts": {
"build": "tsc -p tsconfig.build.json && tsconfig-replace-paths -p tsconfig.build.json -s src/",
"ci:publish": "pnpm publish -r",
"ci:version": "pnpm changeset version",
"dev": "tsc --watch",
"lint": "pnpm eslint .",
"package": "tar -xvf solely-simple-fm-*.tgz && pnpm rimraf ./solely-simple-fm-*.tgz",
"prepublish": "rimraf ./dist && pnpm build",
"preview": "pnpm pack && pnpm package",
"test": "vitest"
}
}
}
<div align="center">
![The Twitter headphone emoji with musical notes in it.][logo]
<a href="https://simple.arciniega.one" title="simple.arciniega.one">
<img
src="public/logo.svg"
height="100"
weight="100"
alt="Headphones with musical notes coming out of it."
title="Headphones with musical notes coming out of it."
/>
</a>

@@ -12,2 +20,4 @@ ## simple-fm

For more information, please visit the [documentation website][docs].
[![CI][actions-image]][actions-link] [![npm-image]][npm-link] [![downloads-image]][npm-link] [![license-image]][license]

@@ -19,3 +29,3 @@

**Node.js 16+** and **TypeScript v5+** is recommended for this package.
`simple-fm` requires that you have **Node.js 18** (and above) and **TypeScript v5+** installed.

@@ -25,2 +35,3 @@ - npm: `npm i @solely/simple-fm`

- yarn: `yarn add @solely/simple-fm`
- bun: `bun i @solely/simple-fm`

@@ -53,254 +64,5 @@ # Notice

```ts
import simpleFM from 'https://esm.sh/@solely/simple-fm';
import SimpleFM from 'https://esm.sh/@solely/simple-fm';
```
# Documentation
## album
### album.getInfo({ artist, album, username? })
_Returns metadata information for an album._
- #### `artist` (string): The name of the artist.
- #### `album` (string): The name of the album.
- #### `username?` (string): The username for the context of the request. If supplied, the user's playcount for this artist's album is included in the response.
### album.getTopTags({ artist, album })
_Returns popular tags for an album._
- #### `artist` (string): The name of the artist.
- #### `album` (string): The name of the album.
### album.search({ album, limit?, page? })
_Search for an album by name._
- #### `album` (string): The name of the album.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 30.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
## artist
### artist.getInfo({ artist, username? })
_Returns metadata information for an artist._
- #### `artist` (string): The artist's name.
- #### `username?` (string): The username for the context of the request. If supplied, the user's playcount for this artist is included in the response.
### artist.getSimilar({ artist, limit? })
_Returns similar artists to this artist._
- #### `artist` (string): The artist's name.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 30.
### artist.getTopAlbums({ artist, limit?, page? })
_Returns popular albums for an artist._
- #### `artist` (string): The artist's name.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### artist.getTopTags({ artist })
_Returns popular tags for an artist._
- #### `artist` (string): The artist's name.
### artist.getTopTracks({ artist, limit?, page? })
_Returns popular tracks for an artist._
- #### `artist` (string): The artist's name.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### artist.search({ artist, limit?, page? })
_Search for an artist by name._
- #### `artist` (string): The artist's name.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 30.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
## chart
### chart.getTopArtists({ limit?, page? })
_Returns the most popular artists._
- #### `limit?` (number): The number of results to fetch per page. Defaults to 30.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### chart.getTopTags({ limit?, page? })
_Returns the most popular tags for tracks._
- #### `limit?` (number): The number of results to fetch per page. Defaults to 30.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### chart.getTopTracks({ limit?, page? })
_Returns the most popular tracks._
- #### `limit?` (number): The number of results to fetch per page. Defaults to 30.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
## geo
### geo.getTopArtists({ country, limit?, page? })
_Returns the most popular artists by country._
- #### `country` (string): The name of the country.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### geo.getTopTracks({ country, limit?, page? })
_Returns the most popular tracks by country._
- #### `country` (string): The name of the country.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
## tag
### tag.getInfo({ tag })
_Returns metadata information on a tag._
- #### `tag` (string): The name of the tag.
### tag.getTopAlbums({ tag, limit?, page? })
- #### `tag` (string): The name of the tag.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### tag.getTopArtists({ tag, limit?, page? })
- #### `tag` (string): The name of the tag.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### tag.getTopTracks({ tag, limit?, page? })
_Returns popular tracks for a tag._
- #### `tag` (string): The name of the tag.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### tag.getWeeklyChartList({ tag })
_Returns a list of available charts for a tag._
- #### `tag` (string): The name of the tag.
## track
### track.getInfo({ artist, track, username? })
_Returns metadata information for a track._
- #### `artist` (string): The name of the artist.
- #### `track` (string): The name of the track.
### track.getSimilar({ artist, track, limit? })
_Returns similar tracks for this track._
- #### `artist` (string): The name of the artist.
- #### `track` (string): The name of the track.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 30.
### track.getTopTags({ artist, track })
_Returns popular tags for a track._
- #### `artist` (string): The name of the artist.
- #### `track` (string): The name of the track.
### track.search({ track, limit?, page? })
_Search for a track by name._
- #### `track` (string): The name of the track.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 30.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
## user
### user.getInfo({ username })
_Returns information about a user's profile._
- #### `username` (string): The name of the user.
### user.getTopArtists({ username, limit?, page? })
_Returns a list of popular artists in a user's library._
- #### `username` (string): The name of the user.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### user.getFriends({ username, limit?, page? })
_Returns a list of the user's friends._
- #### `username` (string): The name of the user.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### user.getLovedTracks({ username, limit?, page? })
_Returns the loved tracks as set by the user._
- #### `username` (string): The name of the user.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### user.getPersonalTags({ username, tag, tagType })
_Returns a list of the user's personal tags._
- #### `username` (string): The name of the user.
- #### `tag` (string): The name of the tag.
- #### `tagType` (album, artist, track): The type of items which have been tagged.
### user.getRecentTracks({ username, limit?, page? })
_Returns the most recent track listened by the user._
- #### `username` (string): The name of the user.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50. Maximum is 200.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### user.getTopAlbums({ username, limit?, page? })
_Returns a list of popular albums in a user's library._
- #### `username` (string): The name of the user.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
### user.getTopTags({ username, limit? })
- #### `username` (string): The name of the user.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
### user.getTopTracks({ username, limit?, page? })
_Returns a list of popular tracks in a user's library._
- #### `username` (string): The name of the user.
- #### `limit?` (number): The number of results to fetch per page. Defaults to 50.
- #### `page?` (number): The page number to fetch. Defaults to the first page.
# License

@@ -313,6 +75,7 @@

[actions-image]:
https://img.shields.io/github/actions/workflow/status/solelychloe/simple-fm/push.yml?colorA=18181B&colorB=de3931
[actions-link]: https://github.com/solelychloe/simple-fm/actions/workflows/push.yml
https://img.shields.io/github/actions/workflow/status/solelychloe/simple-fm/main.yml?colorA=18181B&colorB=de3931
[actions-link]: https://github.com/solelychloe/simple-fm/actions/workflows/main.yml
[deno-repo]: https://github.com/denoland/deno
[logo]: /public/logo.png 'The Twitter headphone emoji with musical notes in it.'
[docs]: https://simple.arciniega.one
[logo]: /public/logo.svg 'The Twitter headphone emoji with musical notes in it.'
[license]: /LICENSE

@@ -319,0 +82,0 @@ [downloads-image]: https://img.shields.io/npm/dm/@solely/simple-fm.svg?style=flat&colorA=18181B&colorB=de3931

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc