@musicorum/lastfm
Advanced tools
Comparing version 0.1.4 to 0.2.0
@@ -11,4 +11,2 @@ import { User } from './packages/User.js'; | ||
apiSecret?: string | undefined; | ||
sessionToken?: string | undefined; | ||
userAgent?: string | undefined; | ||
private apiUrl; | ||
@@ -21,3 +19,4 @@ user: User; | ||
utilities: Utilities; | ||
constructor(apiKey: string, apiSecret?: string | undefined, sessionToken?: string | undefined, userAgent?: string | undefined); | ||
private readonly headers; | ||
constructor(apiKey: string, apiSecret?: string | undefined, userAgent?: string); | ||
onRequestStarted(method: LastfmApiMethod, params: Record<string, string>, internalData: Record<string, never>): void; | ||
@@ -28,3 +27,3 @@ onRequestFinished(method: LastfmApiMethod, params: Record<string, string>, internalData: Record<string, never>, response: Record<string, never>): void; | ||
*/ | ||
request<M extends LastfmApiMethod>(method: M, params?: Record<string, string | (string | undefined)>, signed?: boolean): Promise<GetOriginalResponse<LastfmResponses[M]>>; | ||
request<M extends LastfmApiMethod>(method: M, params?: Record<string, string | number | undefined>, signed?: boolean, write?: boolean): Promise<GetOriginalResponse<LastfmResponses[M]>>; | ||
} |
@@ -13,4 +13,2 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
apiSecret; | ||
sessionToken; | ||
userAgent; | ||
apiUrl = 'https://ws.audioscrobbler.com/2.0'; | ||
@@ -23,9 +21,12 @@ user = new User(this); | ||
utilities = new Utilities(this); | ||
constructor(apiKey, apiSecret, sessionToken, userAgent) { | ||
headers; | ||
constructor(apiKey, apiSecret, userAgent) { | ||
this.apiKey = apiKey; | ||
this.apiSecret = apiSecret; | ||
this.sessionToken = sessionToken; | ||
this.userAgent = userAgent; | ||
if (!apiKey) | ||
throw new Error('apiKey is required and is missing'); | ||
this.headers = { | ||
'User-Agent': userAgent ?? | ||
'Unknown app (@musicorum/lastfm; github.com/musicorum-app/lastfm)' | ||
}; | ||
} | ||
@@ -41,3 +42,3 @@ onRequestStarted(method, params, internalData | ||
*/ | ||
async request(method, params, signed = false) { | ||
async request(method, params, signed = false, write = false) { | ||
if (signed && !this.apiSecret) | ||
@@ -69,8 +70,9 @@ throw new Error('apiSecret is required for signed requests'); | ||
this.onRequestStarted(method, cleanParams, internalData); | ||
const response = await fetch(`${this.apiUrl}?${queryString}`, { | ||
headers: { | ||
'User-Agent': this.userAgent ?? | ||
'Unknown app (@musicorum/lastfm; github.com/musicorum-app/lastfm)' | ||
} | ||
}); | ||
const response = write | ||
? await fetch(`${this.apiUrl}/?format=json`, { | ||
method: 'POST', | ||
headers: this.headers, | ||
body: queryString | ||
}) | ||
: await fetch(`${this.apiUrl}?${queryString}`, { headers: this.headers }); | ||
const data = await response.json(); | ||
@@ -77,0 +79,0 @@ this.onRequestFinished(method, cleanParams, internalData, data); |
@@ -8,2 +8,4 @@ import { LastClient } from '../LastClient.js'; | ||
getInfo(trackName: string, artistName: string, params?: LastfmTrackInfoParams): Promise<GetFormattedResponse<LastfmResponses['track.getInfo']> | undefined>; | ||
love(trackName: string, artistName: string, token: string): Promise<void>; | ||
unlove(trackName: string, artistName: string, token: string): Promise<void>; | ||
} |
@@ -58,2 +58,16 @@ import { parseLastfmImages } from '../utils.js'; | ||
} | ||
async love(trackName, artistName, token) { | ||
await this.client.request('track.love', { | ||
track: trackName, | ||
artist: artistName, | ||
token | ||
}); | ||
} | ||
async unlove(trackName, artistName, token) { | ||
await this.client.request('track.unlove', { | ||
track: trackName, | ||
artist: artistName, | ||
token | ||
}); | ||
} | ||
} |
import type { LastClient } from '../LastClient'; | ||
import PaginatedResult from '../PaginatedResource.js'; | ||
import { LastfmRecentTracksResponse, LastfmRecentTracksTrackResource, LastfmUserRecentTracksParams } from '../types/packages/user'; | ||
import { LastfmRecentTracksResponse, LastfmRecentTracksTrackResource, LastfmUserRecentTracksParams, LastfmUserTopAlbumsParams } from '../types/packages/user'; | ||
import type { GetFormattedResponse, LastfmResponses } from '../types/responses'; | ||
@@ -11,2 +11,3 @@ export declare class User { | ||
getRecentTracksPaginated<EXTENDED extends boolean = false>(user: string, params?: LastfmUserRecentTracksParams): Promise<PaginatedResult<LastfmRecentTracksTrackResource<EXTENDED>>>; | ||
getTopAlbums(user: string, params?: LastfmUserTopAlbumsParams): Promise<GetFormattedResponse<LastfmResponses['user.getTopAlbums']>>; | ||
} |
import PaginatedResult from '../PaginatedResource.js'; | ||
import { parseLastfmImages } from '../utils.js'; | ||
import { parseLastfmImages, parseLastfmPagination } from '../utils.js'; | ||
export class User { | ||
@@ -78,2 +78,20 @@ client; | ||
} | ||
async getTopAlbums(user, params) { | ||
const response = await this.client.request('user.getTopAlbums', { | ||
...params, | ||
user | ||
}); | ||
const albums = response.topalbums.album.map((a) => ({ | ||
name: a.name, | ||
artist: a.artist, | ||
playCount: parseInt(a.playcount), | ||
rank: parseInt(a['@attr'].rank), | ||
mbid: a.mbid, | ||
images: parseLastfmImages(a.image) | ||
})); | ||
return { | ||
albums, | ||
pagination: parseLastfmPagination(response.topalbums['@attr']) | ||
}; | ||
} | ||
} |
@@ -7,2 +7,3 @@ export type StringRecord<K extends string> = Record<K, string>; | ||
} | ||
export type Period = 'overall' | '7day' | '1month' | '3month' | '6month' | '12month'; | ||
export interface LastfmImage { | ||
@@ -30,3 +31,12 @@ size: LastfmImageSize; | ||
}; | ||
export interface PaginationAttributes { | ||
totalPages: number; | ||
page: number; | ||
perPage: number; | ||
total: number; | ||
} | ||
export type PaginatedResponse<I = never> = { | ||
pagination: PaginationAttributes; | ||
} & I; | ||
export type LastfmDate = StringRecord<'uts' | '#text'>; | ||
export type LastfmTag = StringRecord<'name' | 'url'>; |
@@ -1,2 +0,2 @@ | ||
import type { LastfmDate, LastfmImage, LastfmRawImage, PaginatedResponseAttributes, StringRecord } from './common'; | ||
import type { LastfmDate, LastfmImage, LastfmRawImage, PaginatedResponseAttributes, Period, StringRecord } from './common'; | ||
export interface LastfmOriginalUserInfoResponse { | ||
@@ -127,1 +127,47 @@ user: { | ||
} | ||
export interface LastfmUserTopAlbumsParams { | ||
/** | ||
* The time period over which to retrieve top albums for. Defaults for overall | ||
*/ | ||
period?: Period; | ||
/** | ||
* The number of results to fetch per page. Defaults to 50 | ||
*/ | ||
limit?: number; | ||
/** | ||
* The page number to fetch. Defaults to first page | ||
*/ | ||
page?: number; | ||
} | ||
export interface LastfmOriginalUserTopAlbumsResponse { | ||
topalbums: { | ||
album: { | ||
artist: { | ||
url: string; | ||
name: string; | ||
mbid?: string; | ||
}; | ||
image: LastfmRawImage[]; | ||
mbid?: string; | ||
url: string; | ||
playcount: string; | ||
name: string; | ||
'@attr': { | ||
rank: string; | ||
}; | ||
}[]; | ||
'@attr': PaginatedResponseAttributes<'user'>; | ||
}; | ||
} | ||
export interface LastfmUserTopAlbum { | ||
artist: { | ||
url: string; | ||
name: string; | ||
mbid?: string; | ||
}; | ||
name: string; | ||
mbid?: string; | ||
images: LastfmImage[]; | ||
playCount: number; | ||
rank: number; | ||
} |
@@ -1,2 +0,2 @@ | ||
import type { LastfmOriginalUserInfoResponse, LastfmOriginalUserRecentTracksResponse, LastfmOriginalUserTopArtistsResponse, LastfmUserInfo } from './packages/user'; | ||
import type { LastfmOriginalUserInfoResponse, LastfmOriginalUserRecentTracksResponse, LastfmOriginalUserTopAlbumsResponse, LastfmOriginalUserTopArtistsResponse, LastfmUserInfo, LastfmUserTopAlbum } from './packages/user'; | ||
import { LastfmOriginalTrackInfoResponse, LastfmTrackInfo } from './packages/track'; | ||
@@ -6,2 +6,3 @@ import { LastfmAlbumInfo, LastfmOriginalAlbumInfoResponse } from './packages/album'; | ||
import { LastfmAuthGetSessionResponse, LastfmAuthGetTokenResponse, LastfmOriginalAuthGetSessionResponse } from './packages/auth'; | ||
import { PaginatedResponse } from './packages/common'; | ||
export interface LastfmErrorResponse { | ||
@@ -21,2 +22,5 @@ error: number; | ||
'user.getTopArtists': LastfmResponse<LastfmOriginalUserTopArtistsResponse>; | ||
'user.getTopAlbums': LastfmResponse<LastfmOriginalUserTopAlbumsResponse, PaginatedResponse<{ | ||
albums: LastfmUserTopAlbum[]; | ||
}>>; | ||
'track.getInfo': LastfmResponse<LastfmOriginalTrackInfoResponse, LastfmTrackInfo>; | ||
@@ -27,3 +31,5 @@ 'album.getInfo': LastfmResponse<LastfmOriginalAlbumInfoResponse, LastfmAlbumInfo>; | ||
'auth.getSession': LastfmResponse<LastfmOriginalAuthGetSessionResponse, LastfmAuthGetSessionResponse>; | ||
'track.love': LastfmResponse<undefined>; | ||
'track.unlove': LastfmResponse<undefined>; | ||
}; | ||
export type LastfmApiMethod = keyof LastfmResponses; |
@@ -1,2 +0,3 @@ | ||
import { LastfmImage, LastfmRawImage } from './types/packages/common'; | ||
import { LastfmImage, LastfmRawImage, PaginatedResponseAttributes, PaginationAttributes } from './types/packages/common'; | ||
export declare function parseLastfmImages(images: LastfmRawImage[]): LastfmImage[]; | ||
export declare function parseLastfmPagination(original: PaginatedResponseAttributes): PaginationAttributes; |
@@ -9,1 +9,9 @@ export function parseLastfmImages(images) { | ||
} | ||
export function parseLastfmPagination(original) { | ||
return { | ||
page: parseInt(original.page), | ||
totalPages: parseInt(original.totalPages), | ||
perPage: parseInt(original.perPage), | ||
total: parseInt(original.total) | ||
}; | ||
} |
{ | ||
"name": "@musicorum/lastfm", | ||
"version": "0.1.4", | ||
"version": "0.2.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "dist/LastClient.js", |
@@ -25,2 +25,3 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
public utilities = new Utilities(this) | ||
private readonly headers: Record<string, string> | ||
@@ -30,6 +31,11 @@ constructor( | ||
public apiSecret?: string, | ||
public sessionToken?: string, | ||
public userAgent?: string | ||
userAgent?: string | ||
) { | ||
if (!apiKey) throw new Error('apiKey is required and is missing') | ||
this.headers = { | ||
'User-Agent': | ||
userAgent ?? | ||
'Unknown app (@musicorum/lastfm; github.com/musicorum-app/lastfm)' | ||
} | ||
} | ||
@@ -57,4 +63,5 @@ | ||
method: M, | ||
params?: Record<string, string | (string | undefined)>, | ||
signed = false | ||
params?: Record<string, string | number | undefined>, | ||
signed = false, | ||
write = false | ||
) { | ||
@@ -99,9 +106,10 @@ if (signed && !this.apiSecret) | ||
this.onRequestStarted(method, cleanParams, internalData) | ||
const response = await fetch(`${this.apiUrl}?${queryString}`, { | ||
headers: { | ||
'User-Agent': | ||
this.userAgent ?? | ||
'Unknown app (@musicorum/lastfm; github.com/musicorum-app/lastfm)' | ||
} | ||
}) | ||
const response = write | ||
? await fetch(`${this.apiUrl}/?format=json`, { | ||
method: 'POST', | ||
headers: this.headers, | ||
body: queryString | ||
}) | ||
: await fetch(`${this.apiUrl}?${queryString}`, { headers: this.headers }) | ||
const data = await response.json() | ||
@@ -108,0 +116,0 @@ this.onRequestFinished(method, cleanParams, internalData, data) |
@@ -69,2 +69,26 @@ import { LastClient } from '../LastClient.js' | ||
} | ||
async love( | ||
trackName: string, | ||
artistName: string, | ||
token: string | ||
): Promise<void> { | ||
await this.client.request('track.love', { | ||
track: trackName, | ||
artist: artistName, | ||
token | ||
}) | ||
} | ||
async unlove( | ||
trackName: string, | ||
artistName: string, | ||
token: string | ||
): Promise<void> { | ||
await this.client.request('track.unlove', { | ||
track: trackName, | ||
artist: artistName, | ||
token | ||
}) | ||
} | ||
} |
@@ -6,6 +6,8 @@ import type { LastClient } from '../LastClient' | ||
LastfmRecentTracksTrackResource, | ||
LastfmUserRecentTracksParams | ||
LastfmUserRecentTracksParams, | ||
LastfmUserTopAlbum, | ||
LastfmUserTopAlbumsParams | ||
} from '../types/packages/user' | ||
import type { GetFormattedResponse, LastfmResponses } from '../types/responses' | ||
import { parseLastfmImages } from '../utils.js' | ||
import { parseLastfmImages, parseLastfmPagination } from '../utils.js' | ||
@@ -109,2 +111,26 @@ export class User { | ||
} | ||
async getTopAlbums( | ||
user: string, | ||
params?: LastfmUserTopAlbumsParams | ||
): Promise<GetFormattedResponse<LastfmResponses['user.getTopAlbums']>> { | ||
const response = await this.client.request('user.getTopAlbums', { | ||
...params, | ||
user | ||
}) | ||
const albums: LastfmUserTopAlbum[] = response.topalbums.album.map((a) => ({ | ||
name: a.name, | ||
artist: a.artist, | ||
playCount: parseInt(a.playcount), | ||
rank: parseInt(a['@attr'].rank), | ||
mbid: a.mbid, | ||
images: parseLastfmImages(a.image) | ||
})) | ||
return { | ||
albums, | ||
pagination: parseLastfmPagination(response.topalbums['@attr']) | ||
} | ||
} | ||
} |
@@ -15,2 +15,10 @@ export type StringRecord<K extends string> = Record<K, string> | ||
export type Period = | ||
| 'overall' | ||
| '7day' | ||
| '1month' | ||
| '3month' | ||
| '6month' | ||
| '12month' | ||
export interface LastfmImage { | ||
@@ -40,4 +48,15 @@ size: LastfmImageSize | ||
export interface PaginationAttributes { | ||
totalPages: number | ||
page: number | ||
perPage: number | ||
total: number | ||
} | ||
export type PaginatedResponse<I = never> = { | ||
pagination: PaginationAttributes | ||
} & I | ||
export type LastfmDate = StringRecord<'uts' | '#text'> | ||
export type LastfmTag = StringRecord<'name' | 'url'> |
@@ -6,2 +6,3 @@ import type { | ||
PaginatedResponseAttributes, | ||
Period, | ||
StringRecord | ||
@@ -161,1 +162,52 @@ } from './common' | ||
} | ||
// user.getTopAlbums | ||
export interface LastfmUserTopAlbumsParams { | ||
/** | ||
* The time period over which to retrieve top albums for. Defaults for overall | ||
*/ | ||
period?: Period | ||
/** | ||
* The number of results to fetch per page. Defaults to 50 | ||
*/ | ||
limit?: number | ||
/** | ||
* The page number to fetch. Defaults to first page | ||
*/ | ||
page?: number | ||
} | ||
export interface LastfmOriginalUserTopAlbumsResponse { | ||
topalbums: { | ||
album: { | ||
artist: { | ||
url: string | ||
name: string | ||
mbid?: string | ||
} | ||
image: LastfmRawImage[] | ||
mbid?: string | ||
url: string | ||
playcount: string | ||
name: string | ||
'@attr': { | ||
rank: string | ||
} | ||
}[] | ||
'@attr': PaginatedResponseAttributes<'user'> | ||
} | ||
} | ||
export interface LastfmUserTopAlbum { | ||
artist: { | ||
url: string | ||
name: string | ||
mbid?: string | ||
} | ||
name: string | ||
mbid?: string | ||
images: LastfmImage[] | ||
playCount: number | ||
rank: number | ||
} |
import type { | ||
LastfmOriginalUserInfoResponse, | ||
LastfmOriginalUserRecentTracksResponse, | ||
LastfmOriginalUserTopAlbumsResponse, | ||
LastfmOriginalUserTopArtistsResponse, | ||
LastfmUserInfo | ||
LastfmUserInfo, | ||
LastfmUserTopAlbum | ||
} from './packages/user' | ||
@@ -24,2 +26,3 @@ import { | ||
} from './packages/auth' | ||
import { PaginatedResponse } from './packages/common' | ||
@@ -48,2 +51,6 @@ export interface LastfmErrorResponse { | ||
'user.getTopArtists': LastfmResponse<LastfmOriginalUserTopArtistsResponse> | ||
'user.getTopAlbums': LastfmResponse< | ||
LastfmOriginalUserTopAlbumsResponse, | ||
PaginatedResponse<{ albums: LastfmUserTopAlbum[] }> | ||
> | ||
'track.getInfo': LastfmResponse< | ||
@@ -66,4 +73,6 @@ LastfmOriginalTrackInfoResponse, | ||
> | ||
'track.love': LastfmResponse<undefined> | ||
'track.unlove': LastfmResponse<undefined> | ||
} | ||
export type LastfmApiMethod = keyof LastfmResponses |
@@ -1,2 +0,7 @@ | ||
import { LastfmImage, LastfmRawImage } from './types/packages/common' | ||
import { | ||
LastfmImage, | ||
LastfmRawImage, | ||
PaginatedResponseAttributes, | ||
PaginationAttributes | ||
} from './types/packages/common' | ||
@@ -11,1 +16,12 @@ export function parseLastfmImages(images: LastfmRawImage[]): LastfmImage[] { | ||
} | ||
export function parseLastfmPagination( | ||
original: PaginatedResponseAttributes | ||
): PaginationAttributes { | ||
return { | ||
page: parseInt(original.page), | ||
totalPages: parseInt(original.totalPages), | ||
perPage: parseInt(original.perPage), | ||
total: parseInt(original.total) | ||
} | ||
} |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
189147
5312