https://github.com/lmammino/scrobbles
A Node.js library to fetch last.fm "scrobbled" songs for a given user
https://github.com/lmammino/scrobbles
javascript last-fm lastfm lastfm-api music nodejs-modules scrobbles
Last synced: 11 months ago
JSON representation
A Node.js library to fetch last.fm "scrobbled" songs for a given user
- Host: GitHub
- URL: https://github.com/lmammino/scrobbles
- Owner: lmammino
- Created: 2021-03-30T21:06:09.000Z (almost 5 years ago)
- Default Branch: main
- Last Pushed: 2022-03-13T19:30:23.000Z (about 4 years ago)
- Last Synced: 2025-04-23T02:49:22.678Z (11 months ago)
- Topics: javascript, last-fm, lastfm, lastfm-api, music, nodejs-modules, scrobbles
- Language: JavaScript
- Homepage:
- Size: 557 KB
- Stars: 13
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Scrobbles
[](https://npm.im/scrobbles)
[](https://github.com/lmammino/scrobbles/actions/workflows/node.js.yml)
[](https://codecov.io/gh/lmammino/scrobbles)
[](https://standardjs.com)
A Node.js library to fetch [last.fm](https://www.last.fm) "scrobbled" for a given user.
["Scrobble"](https://www.quora.com/How-did-Last-fm-come-with-the-term-scrobble) is a last.fm term to indicate a songs that a user has listened to at a given moment in time. It is effectively a record of a person listening to a specific song!
This library can be useful to explore the entire muscial history of a given user. If you need a few possible use cases, there you go:
- Do some musical analytics. What the most listened song among your friends?
- Backup your entire music listening history somewhere "safe" (for some definition of "safe").
- Search for that one song that you can't fully remember (maybe you just remember the artist or some keyword in the title)!
## Installation
As with any other Node.js package, this is as easy as:
```bash
npm install --save scrobbles
```
## Example
**Note**: In order to use this library you will need to [get an API key from Last.fm](https://www.last.fm/api/account/create).
Print all the musical listening history (from latest to oldest) of the user `loige`:
```javascript
import { RecentTracks } from 'scrobbles'
async function getAllPages () {
const reader = new RecentTracks({
apikey: process.env.API_KEY,
user: 'loige'
})
reader.on('retry', ({ error, message, retryNum, retryAfterMs, url }) => {
console.error(`Failure (${retryNum}) ${url}: ${message}. Retrying in ${retryAfterMs}`)
})
reader.on('progress', console.log)
for await (const page of reader) {
for (const song of page) {
console.log(song)
}
}
}
getAllPages().catch((err) => {
console.error(err)
process.exit(1)
})
```
More examples available in the [`examples` folder](/examples).
## API & Configuration
The library exposes the `RecentTracks` reader class. This class is both an **event emitter** and an **Async Iterator**.
### Initialization options
You can instantiate a new reader you can use the `RecentTracks` constructor which accepts a configuration object:
```javascript
const reader = new RecentTracks({
apikey, // mandatory - the last.fm API key
user, // mandatory - the name of the last.fm user
limit, // optional - the number of songs to fetch per page. Between 1 and 200. Default: 50
from, // optional - a unix timestamp that indicates the earliest point in time to include
// in the list of results. Default: unbound (earliest song ever scrobbled for that user)
to, // optional - a unix timestamp that indicates the latest point in time to include in
// the list of results. Default: unbound (essentially "now")
extended, // optional - a boolean indicating wheter every record should contain extended information
// (e.g. cover pictures) or not. Default: false
mapTrack, // optional - a function to remap the raw response from last.fm. See next sections for more details
maxRetries, // optional - the number of retries in case of failure. Default: 5
retryDelayBaseMs, // optional - the base delay in milliseconds. Default: 100
retryBase, // optional - the exponent to calculate the delay before the next retry: Default: 2
})
```
### Retry logic
Last.fm APIs will sometime throw random errors, so this library provides a built in retry mechanism that can be configured with the options mentioned above.
The wait time before a consecutive retry is calculated with the formula `retryBase ** retryNum * retryDelayBaseMs` (exponential fallback).
If the number of consecutive max retries is reached then an error is thrown.
If a successful response is received after a retry, the retry counter is reset.
### Custom track mapping
By default, iterating over a reader will give you a list of pages. Every page contains a chunk of "scrobbled" tracks. Every track will contain the following fields:
```javascript
{
"album": "The Music That Died Alone",
"artist": "The Tangent",
"date": 1618997643,
"name": "Up-hill From Here",
"url": "https://www.last.fm/music/The+Tangent/_/Up-hill+From+Here",
}
```
In reality, last.fm APIs will contain a lot more information (especially if setting the `extended` option to `true`). If you want to provide your own custom mapping you can do that by passing a custom mapping function using the `mapTrack` parameter of the constructor configuration object.
For example:
```javascript
const reader = new RecentTracks({
apiKey: 'mysupersecretapikey',
user: 'mariobros',
mapTrack: (rawTrack) => ({
date: Number(rawTrack.date.uts),
artist: rawTrack.artist['#text'],
name: rawTrack.name,
album: rawTrack.album['#text'],
url: rawTrack.url,
cover: rawTrack.image.find((i) => i.size === 'extralarge')['#text'],
}),
}
```
To learn more about all the fields exposed by last.fm, check out the official documentation for the [`user.getRecentTracks` API](https://www.last.fm/api/show/user.getRecentTracks).
### Events
A `RecentTracks` instance emits the following events:
#### `progress`
Emitted for every successful api call when a page is fetched. It gives indications about the current progress.
```javascript
reader.on('progress', e => console.log(e))
```
Will print something like this:
```javascript
{
"perPage": 4, // how many elements per page
"remainingPages": 2, // how many pages are left to fetch
"progress": 0.3333333333333333, // the allover progress in percentage
}
```
#### `retry`
In case of error, when a retry is about to happen.
```javascript
reader.on('retry', e => console.log(e))
```
Will print something like this:
```javascript
{
"error": 1, // error code
"maxRetries": 6, // the number of max retries configured
"message": "Unexpected Server Error", // the error message
"retryAfterMs": 1600, // when the next retry is going to happen
"retryNum": 4, // the number of consecutive retries so far
"url": "https://ws.audioscrobbler.com/2.0/?api_key=atestapikey&user=loige&limit=4&extended=0&method=user.getrecenttracks&format=json", // the URL of the request that failed
}
```
## CLI usage
`scrobbles` ships also with a convenient CLI that you can use to easily export data from a given Last.fm account.
You can install the CLI helper globally in your system with:
```bash
npm i -g scrobbles
```
Then it will be available as an executable with the name of `scrobbles.
Alternatively you can install and invoke the executably dynamically through `npx` by just running:
```bash
npx scrobbles
```
Here's an example on how to use `scrobbles` (replace `npx scrobbles` with `scrobbles` if you already installed it globally):
```bash
SCROBBLES_APIKEY=xxx npx scrobbles -u loige -f 1998-01-01 -t 2022-03-14 -F csv > lastfm_export.csv
```
The above example exports all the tracks from 1998-01-01 to 2022-03-14 for user loige in CSV format
You can use the following command to see all the supported options:
```bash
npx scrobbles --help
```
## Contributing
Everyone is very welcome to contribute to this project.
You can contribute just by submitting bugs or suggesting improvements by
[opening an issue on GitHub](https://github.com/lmammino/scrobbles/issues).
## License
Licensed under [MIT License](LICENSE). © Luciano Mammino.