From ed1baadac36a0cbee70592cb0a790b9be4adca3e Mon Sep 17 00:00:00 2001 From: Vendicated Date: Wed, 12 Nov 2025 16:55:36 +0100 Subject: [PATCH] LastFMRichPresence: linkify track/artist/album & make api key optional --- src/plugins/lastfmRichPresence/index.tsx | 94 +++++++++++------------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/src/plugins/lastfmRichPresence/index.tsx b/src/plugins/lastfmRichPresence/index.tsx index 3c36e9dc..e355c361 100644 --- a/src/plugins/lastfmRichPresence/index.tsx +++ b/src/plugins/lastfmRichPresence/index.tsx @@ -17,14 +17,12 @@ */ import { definePluginSettings } from "@api/Settings"; -import { Link } from "@components/Link"; import { Devs } from "@utils/constants"; import { Logger } from "@utils/Logger"; import definePlugin, { OptionType } from "@utils/types"; import { Activity, ActivityAssets, ActivityButton } from "@vencord/discord-types"; import { ActivityFlags, ActivityStatusDisplayType, ActivityType } from "@vencord/discord-types/enums"; -import { findByPropsLazy } from "@webpack"; -import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common"; +import { ApplicationAssetUtils, FluxDispatcher, PresenceStore } from "@webpack/common"; interface TrackData { name: string; @@ -43,15 +41,15 @@ const enum NameFormat { AlbumName = "album" } -const applicationId = "1108588077900898414"; -const placeholderId = "2a96cbd8b46e442fc41c2b86b821562f"; +// Last.fm API keys are essentially public information and have no access to your account, so including one here is fine. +const API_KEY = "790c37d90400163a5a5fe00d6ca32ef0"; +const DISCORD_APP_ID = "1108588077900898414"; +const LASTFM_PLACEHOLDER_IMAGE_HASH = "2a96cbd8b46e442fc41c2b86b821562f"; const logger = new Logger("LastFMRichPresence"); -const PresenceStore = findByPropsLazy("getLocalPresence"); - async function getApplicationAsset(key: string): Promise { - return (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0]; + return (await ApplicationAssetUtils.fetchAssetIds(DISCORD_APP_ID, [key]))[0]; } function setActivity(activity: Activity | null) { @@ -64,25 +62,21 @@ function setActivity(activity: Activity | null) { const settings = definePluginSettings({ username: { - description: "last.fm username", - type: OptionType.STRING, - }, - apiKey: { - description: "last.fm api key", + description: "Last.fm username", type: OptionType.STRING, }, shareUsername: { - description: "show link to last.fm profile", + description: "Show link to Last.fm profile", type: OptionType.BOOLEAN, default: false, }, - shareSong: { - description: "show link to song on last.fm", + clickableLinks: { + description: "Make track, artist and album names clickable links", type: OptionType.BOOLEAN, default: true, }, hideWithSpotify: { - description: "hide last.fm presence if spotify is running", + description: "Hide Last.fm presence if spotify is running", type: OptionType.BOOLEAN, default: true, }, @@ -92,7 +86,7 @@ const settings = definePluginSettings({ default: false, }, statusName: { - description: "custom status text", + description: "Custom status text", type: OptionType.STRING, default: "some music", }, @@ -102,12 +96,12 @@ const settings = definePluginSettings({ options: [ { label: "Don't show (shows generic listening message)", - value: "off", - default: true + value: "off" }, { label: "Show artist name", - value: "artist" + value: "artist", + default: true }, { label: "Show track name", @@ -147,7 +141,7 @@ const settings = definePluginSettings({ ], }, useListeningStatus: { - description: 'show "Listening to" status instead of "Playing"', + description: 'Show "Listening to" status instead of "Playing"', type: OptionType.BOOLEAN, default: false, }, @@ -167,10 +161,14 @@ const settings = definePluginSettings({ ], }, showLastFmLogo: { - description: "show the Last.fm logo by the album cover", + description: "Show the Last.fm logo by the album cover", type: OptionType.BOOLEAN, default: true, - } + }, + apiKey: { + description: "Custom Last.fm API key. You shouldn't need to set this", + type: OptionType.STRING, + }, }); export default definePlugin({ @@ -178,22 +176,6 @@ export default definePlugin({ description: "Little plugin for Last.fm rich presence", authors: [Devs.dzshn, Devs.RuiNtD, Devs.blahajZip, Devs.archeruwu], - settingsAboutComponent: () => ( - <> - How to get an API key - - An API key is required to fetch your current track. To get one, you can - visit this page and - fill in the following information:

- - Application name: Discord Rich Presence
- Application description: (personal use)

- - And copy the API key (not the shared secret!) -
- - ), - settings, start() { @@ -206,13 +188,13 @@ export default definePlugin({ }, async fetchTrackData(): Promise { - if (!settings.store.username || !settings.store.apiKey) + if (!settings.store.username) return null; try { const params = new URLSearchParams({ method: "user.getrecenttracks", - api_key: settings.store.apiKey, + api_key: settings.store.apiKey || API_KEY, user: settings.store.username, limit: "1", format: "json" @@ -252,7 +234,7 @@ export default definePlugin({ }, getLargeImage(track: TrackData): string | undefined { - if (track.imageUrl && !track.imageUrl.includes(placeholderId)) + if (track.imageUrl && !track.imageUrl.includes(LASTFM_PLACEHOLDER_IMAGE_HASH)) return track.imageUrl; if (settings.store.missingArt === "placeholder") @@ -261,13 +243,13 @@ export default definePlugin({ async getActivity(): Promise { if (settings.store.hideWithActivity) { - if (PresenceStore.getActivities().some(a => a.application_id !== applicationId)) { + if (PresenceStore.getActivities().some(a => a.application_id !== DISCORD_APP_ID)) { return null; } } if (settings.store.hideWithSpotify) { - if (PresenceStore.getActivities().some(a => a.type === ActivityType.LISTENING && a.application_id !== applicationId)) { + if (PresenceStore.getActivities().some(a => a.type === ActivityType.LISTENING && a.application_id !== DISCORD_APP_ID)) { // there is already music status because of Spotify or richerCider (probably more) return null; } @@ -298,12 +280,6 @@ export default definePlugin({ url: `https://www.last.fm/user/${settings.store.username}`, }); - if (settings.store.shareSong) - buttons.push({ - label: "View Song", - url: trackData.url, - }); - const statusName = (() => { switch (settings.store.nameFormat) { case NameFormat.ArtistFirst: @@ -321,8 +297,8 @@ export default definePlugin({ } })(); - return { - application_id: applicationId, + const activity: Activity = { + application_id: DISCORD_APP_ID, name: statusName, details: trackData.name, @@ -332,6 +308,7 @@ export default definePlugin({ "artist": ActivityStatusDisplayType.STATE, "track": ActivityStatusDisplayType.DETAILS }[settings.store.statusDisplayType], + assets, buttons: buttons.length ? buttons.map(v => v.label) : undefined, @@ -342,5 +319,16 @@ export default definePlugin({ type: settings.store.useListeningStatus ? ActivityType.LISTENING : ActivityType.PLAYING, flags: ActivityFlags.INSTANCE, }; + + if (settings.store.clickableLinks) { + activity.details_url = trackData.url; + activity.state_url = `https://www.last.fm/music/${encodeURIComponent(trackData.artist)}`; + + if (trackData.album) { + activity.assets!.large_url = `https://www.last.fm/music/${encodeURIComponent(trackData.artist)}/${encodeURIComponent(trackData.album)}`; + } + } + + return activity; } });