From dbcc2a433853f64a228c9e0693e6fa9766653d1f Mon Sep 17 00:00:00 2001 From: kmmiio99o Date: Fri, 2 Jan 2026 19:26:46 +0100 Subject: [PATCH] update showing errors as toast notifications ofc zed thought why not use formatting again <3 --- plugins/Last.fm/src/index.tsx | 130 +++++----- plugins/Last.fm/src/manager.ts | 362 ++++++++++++++-------------- plugins/Last.fm/src/utils/lastfm.ts | 272 ++++++++++----------- 3 files changed, 382 insertions(+), 382 deletions(-) diff --git a/plugins/Last.fm/src/index.tsx b/plugins/Last.fm/src/index.tsx index 5f751ea..7522a36 100644 --- a/plugins/Last.fm/src/index.tsx +++ b/plugins/Last.fm/src/index.tsx @@ -1,9 +1,5 @@ import { plugin } from "@vendetta"; import { FluxDispatcher } from "@vendetta/metro/common"; -import { getAssetIDByName } from "@vendetta/ui/assets"; -import { showToast } from "@vendetta/ui/toasts"; -import { React } from "@vendetta/metro/common"; -import { View } from "react-native"; import { Forms } from "@vendetta/ui/components"; import { LFMSettings } from "../../defs"; @@ -17,10 +13,10 @@ import Settings from "./ui/pages/Settings"; const { FormText } = Forms; export const pluginState = { - pluginStopped: false, - lastActivity: undefined, - updateInterval: undefined, - lastTrackUrl: undefined, + pluginStopped: false, + lastActivity: undefined, + updateInterval: undefined, + lastTrackUrl: undefined, } as { pluginStopped: boolean; lastActivity?: any; @@ -31,18 +27,18 @@ export const pluginState = { // Initialize default settings const defaultSettings: LFMSettings = Constants.DEFAULT_SETTINGS; for (const key in defaultSettings) { - plugin.storage[key] = + plugin.storage[key] = plugin.storage[key] ?? defaultSettings[key as keyof typeof defaultSettings]; } export const currentSettings = new Proxy(plugin.storage, { - get(target, prop) { - return target[prop]; - }, - set(target, prop, value) { - target[prop] = value; - return true; - }, + get(target, prop) { + return target[prop]; + }, + set(target, prop, value) { + target[prop] = value; + return true; + }, }); // Connection status tracking @@ -51,62 +47,66 @@ const MAX_CONNECTION_ATTEMPTS = 3; const RECONNECT_DELAY = 5000; async function tryInitialize() { - try { - await initialize(); - connectionAttempts = 0; - } catch (error) { - console.error("[Last.fm] Initialization error:", error); - connectionAttempts++; + try { + await initialize(); + connectionAttempts = 0; + console.log("[Last.fm] Successfully connected to Last.fm"); + } catch (error) { + console.error("[Last.fm] Initialization error:", error); + connectionAttempts++; - if (connectionAttempts < MAX_CONNECTION_ATTEMPTS) { - showToast("Retrying connection...", getAssetIDByName("ic_clock")); - setTimeout(tryInitialize, RECONNECT_DELAY); - } else { - showToast("Failed to connect to Last.fm", getAssetIDByName("Small")); - } + if (connectionAttempts < MAX_CONNECTION_ATTEMPTS) { + console.log( + `[Last.fm] Retrying connection... (attempt ${connectionAttempts})`, + ); + setTimeout(tryInitialize, RECONNECT_DELAY); + } else { + console.error( + "[Last.fm] Failed to connect to Last.fm after multiple attempts", + ); } + } } export default { - onLoad() { - pluginState.pluginStopped = false; + onLoad() { + pluginState.pluginStopped = false; - if (!currentSettings.username || !currentSettings.apiKey) { - showToast( - "Please configure Last.fm username and API key in settings", - getAssetIDByName("ic_warning"), - ); - return; - } + if (!currentSettings.username || !currentSettings.apiKey) { + console.log( + "[Last.fm] Please configure Last.fm username and API key in settings", + ); + return; + } + if (UserStore.getCurrentUser()) { + tryInitialize(); + } else { + const waitForUser = () => { if (UserStore.getCurrentUser()) { - tryInitialize(); - } else { - const waitForUser = () => { - if (UserStore.getCurrentUser()) { - tryInitialize(); - FluxDispatcher.unsubscribe("CONNECTION_OPEN", waitForUser); - } - }; + tryInitialize(); + FluxDispatcher.unsubscribe("CONNECTION_OPEN", waitForUser); + } + }; - FluxDispatcher.subscribe("CONNECTION_OPEN", waitForUser); - } - }, - onUnload() { - pluginState.pluginStopped = true; - stop(); - }, - // Handle settings updates - onSettingsUpdate(newSettings: any) { - Object.assign(currentSettings, newSettings); - tryInitialize(); - }, - // Handle Discord reconnection - onDiscordReconnect() { - if (!pluginState.pluginStopped) { - tryInitialize(); - } - }, - // Settings component - settings: Settings, + FluxDispatcher.subscribe("CONNECTION_OPEN", waitForUser); + } + }, + onUnload() { + pluginState.pluginStopped = true; + stop(); + }, + // Handle settings updates + onSettingsUpdate(newSettings: any) { + Object.assign(currentSettings, newSettings); + tryInitialize(); + }, + // Handle Discord reconnection + onDiscordReconnect() { + if (!pluginState.pluginStopped) { + tryInitialize(); + } + }, + // Settings component + settings: Settings, }; diff --git a/plugins/Last.fm/src/manager.ts b/plugins/Last.fm/src/manager.ts index 3ca14d3..51576b3 100644 --- a/plugins/Last.fm/src/manager.ts +++ b/plugins/Last.fm/src/manager.ts @@ -1,6 +1,3 @@ -import { getAssetIDByName } from "@vendetta/ui/assets"; -import { showToast } from "@vendetta/ui/toasts"; - import { currentSettings, pluginState } from "."; import { Activity } from "../../defs"; import Constants from "./constants"; @@ -9,9 +6,9 @@ import { clearActivity, fetchAsset, sendRequest } from "./utils/activity"; import { setDebugInfo } from "./utils/debug"; function formatTime(seconds: number): string { - const minutes = Math.floor(seconds / 60); - const remainingSeconds = Math.floor(seconds % 60); - return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`; + const minutes = Math.floor(seconds / 60); + const remainingSeconds = Math.floor(seconds % 60); + return `${minutes}:${remainingSeconds.toString().padStart(2, "0")}`; } import { lastfmClient } from "./utils/lastfm"; @@ -23,210 +20,211 @@ enum ActivityType { } const verboseLog = (...message: any[]) => - currentSettings.verboseLogging && console.log("[Last.fm]", ...message); + currentSettings.verboseLogging && console.log("[Last.fm]", ...message); class PluginManager { - private static instance: PluginManager; - private updateTimer?: NodeJS.Timer; - private reconnectTimer?: NodeJS.Timer; - private consecutiveFailures = 0; - private isReconnecting = false; + private static instance: PluginManager; + private updateTimer?: NodeJS.Timer; + private reconnectTimer?: NodeJS.Timer; + private consecutiveFailures = 0; + private isReconnecting = false; - private constructor() {} + private constructor() {} - public static getInstance(): PluginManager { - if (!PluginManager.instance) { - PluginManager.instance = new PluginManager(); - } - return PluginManager.instance; + public static getInstance(): PluginManager { + if (!PluginManager.instance) { + PluginManager.instance = new PluginManager(); } + return PluginManager.instance; + } - /** + /** * Updates the Discord activity with the current Last.fm track */ - private async updateActivity() { - if (pluginState.pluginStopped) { - verboseLog("Plugin is stopped, skipping update"); - this.stopUpdates(); - return; - } - - verboseLog("Fetching last track..."); - - try { - if (!currentSettings.username || !currentSettings.apiKey) { - throw new Error("Username or API key not set"); - } - - if (currentSettings.ignoreSpotify) { - const spotifyActivity = SelfPresenceStore.findActivity( - (act) => act.sync_id, - ); - if (spotifyActivity) { - verboseLog("Spotify is currently playing, clearing activity"); - setDebugInfo("isSpotifyIgnored", true); - clearActivity(); - return; - } - setDebugInfo("isSpotifyIgnored", false); - } - - const lastTrack = await lastfmClient.fetchLatestScrobble(); - setDebugInfo("lastTrack", lastTrack); - - if (!lastTrack.nowPlaying) { - verboseLog("Last track is not currently playing"); - clearActivity(); - return; - } - - if (pluginState.lastTrackUrl === lastTrack.url) { - verboseLog("Track hasn't changed"); - return; - } - - const activity: Activity = { - name: currentSettings.appName || Constants.DEFAULT_APP_NAME, - flags: 0, - type: currentSettings.listeningTo - ? ActivityType.LISTENING - : ActivityType.PLAYING, - details: lastTrack.name, - state: `by ${lastTrack.artist}`, - status_display_type: 1, - application_id: Constants.APPLICATION_ID, - }; - - // Handle dynamic app name - if (activity.name.includes("{{")) { - for (const key in lastTrack) { - activity.name = activity.name.replace( - `{{${key}}}`, - lastTrack[key as keyof typeof lastTrack] || "", - ); - } - } - - // Set timestamps if enabled - // Use `from` and `to` from track.getInfo - if (currentSettings.showTimestamp && typeof lastTrack.from === "number") { - activity.timestamps = { - start: lastTrack.from * 1000, - ...(typeof lastTrack.to === "number" && { end: lastTrack.to * 1000 }), - }; - } - - // Handle album art - if (lastTrack.album) { - const asset = await fetchAsset([lastTrack.albumArt]); - if (asset[0]) { - activity.assets = { - large_image: asset[0], - large_text: `on ${lastTrack.album}${ - currentSettings.showTimestamp && lastTrack.to - ? ` • ${formatTime((lastTrack.to - lastTrack.from) / 1000)}` - : "" - }`, - }; - } - } - - verboseLog("Setting activity:", activity); - setDebugInfo("lastActivity", activity); - - await sendRequest(activity); - pluginState.lastTrackUrl = lastTrack.url; - pluginState.lastActivity = activity; - this.consecutiveFailures = 0; - - verboseLog("Activity set successfully!"); - } catch (error) { - console.error("[Last.fm] Update error:", error); - this.handleError(error); - } + private async updateActivity() { + if (pluginState.pluginStopped) { + verboseLog("Plugin is stopped, skipping update"); + this.stopUpdates(); + return; } - private handleError(error: Error) { - this.consecutiveFailures++; - setDebugInfo("lastError", error); + verboseLog("Fetching last track..."); - if (this.consecutiveFailures >= Constants.MAX_RETRY_ATTEMPTS) { - verboseLog( - `Failed ${this.consecutiveFailures} times, initiating reconnection...`, - ); - this.startReconnection(); + try { + if (!currentSettings.username || !currentSettings.apiKey) { + throw new Error("Username or API key not set"); + } + + if (currentSettings.ignoreSpotify) { + const spotifyActivity = SelfPresenceStore.findActivity( + (act) => act.sync_id, + ); + if (spotifyActivity) { + verboseLog("Spotify is currently playing, clearing activity"); + setDebugInfo("isSpotifyIgnored", true); + clearActivity(); + return; } - } + setDebugInfo("isSpotifyIgnored", false); + } - private startReconnection() { - if (this.isReconnecting) return; + const lastTrack = await lastfmClient.fetchLatestScrobble(); + setDebugInfo("lastTrack", lastTrack); - this.isReconnecting = true; - this.stopUpdates(); + if (!lastTrack.nowPlaying) { + verboseLog("Last track is not currently playing"); + clearActivity(); + return; + } - verboseLog("Starting reconnection process"); - this.reconnectTimer = setInterval(() => { - verboseLog("Attempting to reconnect..."); - this.initialize() - .then(() => { - verboseLog("Reconnection successful"); - this.stopReconnection(); - }) - .catch((error) => { - verboseLog("Reconnection failed:", error); - }); - }, Constants.RETRY_DELAY); - } + if (pluginState.lastTrackUrl === lastTrack.url) { + verboseLog("Track hasn't changed"); + return; + } - private stopReconnection() { - if (this.reconnectTimer) { - clearInterval(this.reconnectTimer); - this.reconnectTimer = undefined; + const activity: Activity = { + name: currentSettings.appName || Constants.DEFAULT_APP_NAME, + flags: 0, + type: currentSettings.listeningTo + ? ActivityType.LISTENING + : ActivityType.PLAYING, + details: lastTrack.name, + state: `by ${lastTrack.artist}`, + status_display_type: 1, + application_id: Constants.APPLICATION_ID, + }; + + // Handle dynamic app name + if (activity.name.includes("{{")) { + for (const key in lastTrack) { + activity.name = activity.name.replace( + `{{${key}}}`, + lastTrack[key as keyof typeof lastTrack] || "", + ); } - this.isReconnecting = false; - this.consecutiveFailures = 0; - } + } - /** + // Set timestamps if enabled + // Use `from` and `to` from track.getInfo + if (currentSettings.showTimestamp && typeof lastTrack.from === "number") { + activity.timestamps = { + start: lastTrack.from * 1000, + ...(typeof lastTrack.to === "number" && { end: lastTrack.to * 1000 }), + }; + } + + // Handle album art + if (lastTrack.album) { + const asset = await fetchAsset([lastTrack.albumArt]); + if (asset[0]) { + activity.assets = { + large_image: asset[0], + large_text: `on ${lastTrack.album}${ + currentSettings.showTimestamp && lastTrack.to + ? ` • ${formatTime((lastTrack.to - lastTrack.from) / 1000)}` + : "" + }`, + }; + } + } + + verboseLog("Setting activity:", activity); + setDebugInfo("lastActivity", activity); + + await sendRequest(activity); + pluginState.lastTrackUrl = lastTrack.url; + pluginState.lastActivity = activity; + this.consecutiveFailures = 0; + + verboseLog("Activity set successfully!"); + } catch (error) { + console.error("[Last.fm] Update error:", error); + this.handleError(error); + } + } + + private handleError(error: Error) { + this.consecutiveFailures++; + setDebugInfo("lastError", error); + + if (this.consecutiveFailures >= Constants.MAX_RETRY_ATTEMPTS) { + console.log( + `[Last.fm] Failed ${this.consecutiveFailures} times, initiating reconnection...`, + ); + this.startReconnection(); + } + } + + private startReconnection() { + if (this.isReconnecting) return; + + this.isReconnecting = true; + this.stopUpdates(); + + console.log("[Last.fm] Starting reconnection process"); + this.reconnectTimer = setInterval(() => { + console.log("[Last.fm] Attempting to reconnect..."); + this.initialize() + .then(() => { + console.log("[Last.fm] Reconnection successful"); + this.stopReconnection(); + }) + .catch((error) => { + console.log("[Last.fm] Reconnection failed:", error); + }); + }, Constants.RETRY_DELAY); + } + + private stopReconnection() { + if (this.reconnectTimer) { + clearInterval(this.reconnectTimer); + this.reconnectTimer = undefined; + } + this.isReconnecting = false; + this.consecutiveFailures = 0; + } + + /** * Stops all update and reconnection timers */ - private stopUpdates() { - if (this.updateTimer) { - clearInterval(this.updateTimer); - this.updateTimer = undefined; - } + private stopUpdates() { + if (this.updateTimer) { + clearInterval(this.updateTimer); + this.updateTimer = undefined; } + } - /** + /** * Initializes the plugin and starts the update loop */ - public async initialize() { - if (pluginState.pluginStopped) { - throw new Error("Plugin is stopped"); - } - - this.stopUpdates(); - await this.updateActivity(); - - const interval = Math.max( - (Number(currentSettings.timeInterval) || - Constants.DEFAULT_SETTINGS.timeInterval) * 1000, - Constants.MIN_UPDATE_INTERVAL * 1000, - ); - - this.updateTimer = setInterval(() => this.updateActivity(), interval); - verboseLog(`Update timer started with interval: ${interval}ms`); + public async initialize() { + if (pluginState.pluginStopped) { + throw new Error("Plugin is stopped"); } - /** + this.stopUpdates(); + await this.updateActivity(); + + const interval = Math.max( + (Number(currentSettings.timeInterval) || + Constants.DEFAULT_SETTINGS.timeInterval) * 1000, + Constants.MIN_UPDATE_INTERVAL * 1000, + ); + + this.updateTimer = setInterval(() => this.updateActivity(), interval); + console.log(`[Last.fm] Update timer started with interval: ${interval}ms`); + } + + /** * Stops the plugin and cleans up */ - public stop() { - pluginState.pluginStopped = true; - this.stopUpdates(); - this.stopReconnection(); - clearActivity(); - } + public stop() { + pluginState.pluginStopped = true; + this.stopUpdates(); + this.stopReconnection(); + clearActivity(); + console.log("[Last.fm] Plugin stopped"); + } } // Export singleton instance methods diff --git a/plugins/Last.fm/src/utils/lastfm.ts b/plugins/Last.fm/src/utils/lastfm.ts index fb7d621..c3407f9 100644 --- a/plugins/Last.fm/src/utils/lastfm.ts +++ b/plugins/Last.fm/src/utils/lastfm.ts @@ -2,8 +2,6 @@ import { currentSettings } from ".."; import { Track } from "../../../defs"; import Constants from "../constants"; import { setDebugInfo } from "./debug"; -import { showToast } from "@vendetta/ui/toasts"; -import { getAssetIDByName } from "@vendetta/ui/assets"; interface LastFMError { error: number; @@ -44,161 +42,165 @@ interface LastFMTrack { } class LastFMClient { - private static instance: LastFMClient; - private retryCount = 0; - private lastError = 0; + private static instance: LastFMClient; + private retryCount = 0; + private lastError = 0; - private constructor() {} + private constructor() {} - public static getInstance(): LastFMClient { - if (!LastFMClient.instance) { - LastFMClient.instance = new LastFMClient(); - } - return LastFMClient.instance; + public static getInstance(): LastFMClient { + if (!LastFMClient.instance) { + LastFMClient.instance = new LastFMClient(); } + return LastFMClient.instance; + } - private validateSettings(): void { - if (!currentSettings.username) { - throw new Error("Last.fm username is not set"); - } - if (!currentSettings.apiKey) { - throw new Error("Last.fm API key is not set"); - } + private validateSettings(): void { + if (!currentSettings.username) { + throw new Error("Last.fm username is not set"); } + if (!currentSettings.apiKey) { + throw new Error("Last.fm API key is not set"); + } + } - private async handleError(error: LastFMError): Promise { - this.lastError = error.error; + private async handleError(error: LastFMError): Promise { + this.lastError = error.error; - const errorMessages: { [key: number]: string } = { - 2: "Invalid API key", - 11: "Service temporarily unavailable", - 16: "Service temporarily unavailable", - 29: "Rate limit exceeded", - }; + const errorMessages: { [key: number]: string } = { + 2: "Invalid API key", + 11: "Service temporarily unavailable", + 16: "Service temporarily unavailable", + 29: "Rate limit exceeded", + }; - const message = + const message = errorMessages[error.error] || error.message || "Unknown error"; - showToast(`Last.fm Error: ${message}`, getAssetIDByName("Small")); - throw new Error(`Last.fm API Error ${error.error}: ${message}`); + // Log instead of showing toast + console.log(`[Last.fm] API Error ${error.error}: ${message}`); + + throw new Error(`Last.fm API Error ${error.error}: ${message}`); + } + + private async makeRequest( + params: Record, + ): Promise { + const queryParams = new URLSearchParams({ + ...params, + api_key: currentSettings.apiKey, + format: "json", + }).toString(); + + const response = await fetch( + `${Constants.LFM_API_BASE_URL}?${queryParams}`, + ); + const data: LastFMResponse = await response.json(); + + if (!response.ok || data.error) { + await this.handleError(data as LastFMError); } - private async makeRequest( - params: Record, - ): Promise { - const queryParams = new URLSearchParams({ - ...params, - api_key: currentSettings.apiKey, - format: "json", - }).toString(); + return data; + } - const response = await fetch( - `${Constants.LFM_API_BASE_URL}?${queryParams}`, - ); - const data: LastFMResponse = await response.json(); - - if (!response.ok || data.error) { - await this.handleError(data as LastFMError); - } - - return data; - } - - public async fetchLatestScrobble(): Promise< + public async fetchLatestScrobble(): Promise< Track & { from: number; to: number | null } - > { - try { - this.validateSettings(); + > { + try { + this.validateSettings(); - const data = await this.makeRequest({ - method: "user.getrecenttracks", - user: currentSettings.username, - limit: "1", - extended: "1", - }); + const data = await this.makeRequest({ + method: "user.getrecenttracks", + user: currentSettings.username, + limit: "1", + extended: "1", + }); - const lastTrack = data?.recenttracks?.track?.[0]; - setDebugInfo("lastAPIResponse", lastTrack); + const lastTrack = data?.recenttracks?.track?.[0]; + setDebugInfo("lastAPIResponse", lastTrack); - if (!lastTrack) { - throw new Error("No tracks found"); - } + if (!lastTrack) { + console.log("[Last.fm] No tracks found for user"); + throw new Error("No tracks found"); + } - // Reset retry count on successful request - this.retryCount = 0; + // Reset retry count on successful request + this.retryCount = 0; - const isNowPlaying = Boolean(lastTrack["@attr"]?.nowplaying); - const from = isNowPlaying - ? Math.floor(Date.now() / 1000) - : parseInt(lastTrack?.date?.uts); + const isNowPlaying = Boolean(lastTrack["@attr"]?.nowplaying); + const from = isNowPlaying + ? Math.floor(Date.now() / 1000) + : parseInt(lastTrack?.date?.uts); - let to: number | null = null; - try { - const trackInfo = await this.makeRequest({ - method: "track.getInfo", - track: lastTrack.name, - artist: lastTrack.artist.name, - username: currentSettings.username, - }); + let to: number | null = null; + try { + const trackInfo = await this.makeRequest({ + method: "track.getInfo", + track: lastTrack.name, + artist: lastTrack.artist.name, + username: currentSettings.username, + }); - const duration = parseInt(trackInfo?.track?.duration); - if (duration > 0) { - to = from + Math.floor(duration / 1000); - } - } catch (err) { - console.warn("Failed to fetch track duration", err); - } - - return { - name: lastTrack.name, - artist: lastTrack.artist.name, - album: lastTrack.album["#text"], - albumArt: await this.handleAlbumCover( - lastTrack.image?.find((x) => x.size === "large")?.["#text"], - ), - url: lastTrack.url, - date: lastTrack.date?.["#text"] ?? "now", - nowPlaying: isNowPlaying, - loved: lastTrack.loved === "1", - from, - to, - }; - } catch (error) { - // Increment retry count and throw if we've exceeded max retries - this.retryCount++; - if (this.retryCount > Constants.MAX_RETRY_ATTEMPTS) { - this.retryCount = 0; - throw error; - } - - // Wait before retrying - await new Promise((resolve) => - setTimeout(resolve, Constants.RETRY_DELAY), - ); - return this.fetchLatestScrobble(); + const duration = parseInt(trackInfo?.track?.duration); + if (duration > 0) { + to = from + Math.floor(duration / 1000); } - } + } catch (err) { + console.warn("[Last.fm] Failed to fetch track duration", err); + } - private async handleAlbumCover(cover?: string): Promise { - if (!cover) return null; - - // If the cover is a default one, return null - if ( - Constants.LFM_DEFAULT_COVER_HASHES.some((hash) => cover.includes(hash)) - ) { - return null; - } - - return cover; - } - - public getLastError(): number { - return this.lastError; - } - - public resetRetryCount(): void { + return { + name: lastTrack.name, + artist: lastTrack.artist.name, + album: lastTrack.album["#text"], + albumArt: await this.handleAlbumCover( + lastTrack.image?.find((x) => x.size === "large")?.["#text"], + ), + url: lastTrack.url, + date: lastTrack.date?.["#text"] ?? "now", + nowPlaying: isNowPlaying, + loved: lastTrack.loved === "1", + from, + to, + }; + } catch (error) { + // Increment retry count and throw if we've exceeded max retries + this.retryCount++; + if (this.retryCount > Constants.MAX_RETRY_ATTEMPTS) { this.retryCount = 0; + console.error("[Last.fm] Max retry attempts reached"); + throw error; + } + + // Wait before retrying + await new Promise((resolve) => + setTimeout(resolve, Constants.RETRY_DELAY), + ); + return this.fetchLatestScrobble(); } + } + + private async handleAlbumCover(cover?: string): Promise { + if (!cover) return null; + + // If the cover is a default one, return null + if ( + Constants.LFM_DEFAULT_COVER_HASHES.some((hash) => cover.includes(hash)) + ) { + return null; + } + + return cover; + } + + public getLastError(): number { + return this.lastError; + } + + public resetRetryCount(): void { + this.retryCount = 0; + } } // Export a singleton instance @@ -207,8 +209,8 @@ export const lastfmClient = LastFMClient.getInstance(); /** Fetches the latest user's scrobble */ export async function fetchLatestScrobble(): Promise< Track & { from: number; to: number | null } - > { - return lastfmClient.fetchLatestScrobble(); +> { + return lastfmClient.fetchLatestScrobble(); } /** @@ -216,5 +218,5 @@ export async function fetchLatestScrobble(): Promise< * @param cover The album cover given by Last.fm */ export async function handleAlbumCover(cover: string): Promise { - return lastfmClient.handleAlbumCover(cover); + return lastfmClient.handleAlbumCover(cover); }