@solely/simple-fm
Advanced tools
Comparing version 1.5.3 to 1.6.0
@@ -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" | ||
} | ||
} | ||
} |
273
README.md
<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 |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
77
2632
0
0
90587
19
82