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, }],