diff --git a/README.md b/README.md
index ce0f5089..4a613927 100644
--- a/README.md
+++ b/README.md
@@ -901,6 +901,13 @@ Finish the plugin setup by adding the following to your workflow:
+
+Last.fm
+
+This mode is not supported for now.
+
+
+
#### Recently played mode
@@ -994,6 +1001,37 @@ With your `client_id`, `client_secret` and `refresh_token` you can finish the pl
+
+Last.fm
+
+Obtain a Last.fm API key.
+
+To do so, you can simply [create an API account](https://www.last.fm/api/account/create) or [use an existing one](https://www.last.fm/api/accounts).
+
+Finish the plugin setup by adding the following to your workflow:
+```yaml
+- uses: lowlighter/metrics@latest
+ with:
+ # ... other options
+ plugin_music: yes
+ plugin_music_provider: lastfm
+ plugin_music_token: ${{ secrets.LASTFM_API_KEY }}
+ plugin_music_mode: recent
+ plugin_music_limit: 4
+```
+
+It is possible to use a different Last.fm username from your GitHub account by using `plugin_music_user` option.
+
+Add the following to your workflow:
+```yaml
+- uses: lowlighter/metrics@latest
+ with:
+ # ... other options
+ plugin_music_user: ********
+```
+
+
+
### 🈷️ Languages
diff --git a/action.yml b/action.yml
index 2a1ae101..b08ecaad 100644
--- a/action.yml
+++ b/action.yml
@@ -240,6 +240,7 @@ inputs:
# Supported values are :
# - "apple" for Apple Music
# - "spotify" for Spotify
+ # - "lastfm" for Last.fm
plugin_music_provider:
description: Name of the music provider you're using
default: ""
@@ -248,6 +249,7 @@ inputs:
# This may be required depending on the music provider and the mode you use
# - "apple" : not required
# - "spotify" : required for "recent" mode, format is "client_id, client_secret, refresh_token"
+ # - "lastfm" : required, format is "api_key"
plugin_music_token:
description: Music provider personal token
default: ""
@@ -272,6 +274,12 @@ inputs:
description: Number of tracks to display
default: 4
+ # Music service username
+ # Leave empty to default to the login "user"'s GitHub account
+ plugin_music_user:
+ description: "Music provider username"
+ default: ""
+
# Posts plugin
# Display recent posts from an external source
plugin_posts:
diff --git a/source/app/action/index.mjs b/source/app/action/index.mjs
index ee358cc4..df066a96 100644
--- a/source/app/action/index.mjs
+++ b/source/app/action/index.mjs
@@ -180,7 +180,7 @@
if (plugins.music.enabled) {
plugins.music.token = input.string("plugin_music_token")
info("Music token", plugins.music.token, {token:true})
- for (const option of ["provider", "mode", "playlist"])
+ for (const option of ["provider", "mode", "playlist", "user"])
info(`Music ${option}`, q[`music.${option}`] = input.string(`plugin_music_${option}`))
for (const option of ["limit"])
info(`Music ${option}`, q[`music.${option}`] = input.number(`plugin_music_${option}`))
diff --git a/source/app/mocks.mjs b/source/app/mocks.mjs
index 89663543..a971b1f6 100644
--- a/source/app/mocks.mjs
+++ b/source/app/mocks.mjs
@@ -1083,6 +1083,69 @@
})
}
}
+ //Last.fm api
+ if (/^https:..ws.audioscrobbler.com/.test(url)) {
+ //Get recently played tracks
+ if (/user.getrecenttracks/.test(url)) {
+ console.debug(`metrics/compute/mocks > mocking lastfm api result > ${url}`)
+ const artist = faker.random.word()
+ const album = faker.random.words(3)
+ const track = faker.random.words(5)
+ const date = faker.date.recent()
+ return ({
+ status:200,
+ data:{
+ recenttracks:{
+ "@attr":{
+ page:"1",
+ perPage:"1",
+ user:"RJ",
+ total:"100",
+ pages:"100",
+ },
+ track:[
+ {
+ artist:{
+ mbid:"",
+ "#text":artist,
+ },
+ album:{
+ mbid:"",
+ "#text":album,
+ },
+ image:[
+ {
+ size:"small",
+ "#text":faker.image.abstract(),
+ },
+ {
+ size:"medium",
+ "#text":faker.image.abstract(),
+ },
+ {
+ size:"large",
+ "#text":faker.image.abstract(),
+ },
+ {
+ size:"extralarge",
+ "#text":faker.image.abstract(),
+ },
+ ],
+ streamable:"0",
+ date:{
+ uts:Math.floor(date.getTime() / 1000),
+ "#text":date.toUTCString().slice(5, 22),
+ },
+ url:faker.internet.url(),
+ name:track,
+ mbid:"",
+ },
+ ],
+ },
+ },
+ })
+ }
+ }
//Twitter api
if (/^https:..api.twitter.com/.test(url)) {
//Get user profile
diff --git a/source/app/web/statics/app.js b/source/app/web/statics/app.js
index fbe8c0c9..eaffea9c 100644
--- a/source/app/web/statics/app.js
+++ b/source/app/web/statics/app.js
@@ -94,8 +94,10 @@
"habits.days":{text:"Max events age", type:"number", min:1, max:30},
"habits.facts":{text:"Display facts", type:"boolean"},
"habits.charts":{text:"Display charts", type:"boolean"},
+ "music.provider":{text:"Provider", placeholder:"spotify"},
"music.playlist":{text:"Playlist url", placeholder:"https://embed.music.apple.com/en/playlist/"},
"music.limit":{text:"Limit", type:"number", min:1, max:100},
+ "music.user":{text:"Username", placeholder:"(default to GitHub login)"},
"posts.limit":{text:"Limit", type:"number", min:1, max:30},
"posts.user":{text:"Username", placeholder:"(default to GitHub login)"},
"posts.source":{text:"Source", type:"select", values:["dev.to"]},
@@ -124,8 +126,10 @@
"habits.days":14,
"habits.facts":true,
"habits.charts":false,
+ "music.provider":"",
"music.playlist":"",
"music.limit":4,
+ "music.user":"",
"posts.limit":4,
"posts.user":"",
"posts.source":"dev.to",
diff --git a/source/plugins/music/index.mjs b/source/plugins/music/index.mjs
index b4d725fc..a0d487ce 100644
--- a/source/plugins/music/index.mjs
+++ b/source/plugins/music/index.mjs
@@ -8,6 +8,10 @@
name:"Spotify",
embed:/^https:..open.spotify.com.embed.playlist/,
},
+ lastfm:{
+ name:"Last.fm",
+ embed:/^\b$/,
+ },
}
//Supported modes
@@ -30,7 +34,7 @@
}
let tracks = null
//Parameters override
- let {"music.provider":provider = "", "music.mode":mode = "", "music.playlist":playlist = null, "music.limit":limit = 4} = q
+ let {"music.provider":provider = "", "music.mode":mode = "", "music.playlist":playlist = null, "music.limit":limit = 4, "music.user":user = login} = q
//Auto-guess parameters
if ((playlist)&&(!mode))
mode = "playlist"
@@ -156,6 +160,33 @@
}
break
}
+ //Last.fm
+ case "lastfm":{
+ //API call and parse tracklist
+ try {
+ console.debug(`metrics/compute/${login}/plugins > music > querying lastfm api`)
+ tracks = (await imports.axios.get(`https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=${user}&api_key=${token}&limit=${limit}&format=json`, {headers:{
+ "Accept":"application/json",
+ "User-Agent":"lowlighter/metrics"}
+ })).data.recenttracks.track.map((track) => ({
+ name:track.name,
+ artist:track.artist["#text"],
+ artwork:track.image.reverse()[0]["#text"],
+ }))
+ }
+ //Handle errors
+ catch (error) {
+ if (error.isAxiosError) {
+ const status = error.response?.status
+ const description = error.response.data?.message ?? null
+ const message = `API returned ${status}${description ? ` (${description})` : ""}`
+ error = error.response?.data ?? null
+ throw {error:{message, instance:error}, ...raw}
+ }
+ throw error
+ }
+ break
+ }
//Unsupported
default:
throw {error:{message:`Unsupported mode "${mode}" for provider "${provider}"`}, ...raw}
diff --git a/tests/metrics.test.js b/tests/metrics.test.js
index c7c8e250..b064ba28 100644
--- a/tests/metrics.test.js
+++ b/tests/metrics.test.js
@@ -127,6 +127,11 @@
plugin_music:true,
plugin_music_provider: "spotify",
}, {skip:["terminal", "repository"]}],
+ ["Music plugin (recent - lastfm)", {
+ plugin_music:true,
+ plugin_music_provider: "lastfm",
+ plugin_music_user: "RJ",
+ }, {skip:["terminal", "repository"]}],
["Language plugin (default)", {
plugin_languages:true,
}],