Last.fm: use storage

This commit is contained in:
amsyarasyiq 2023-02-12 16:33:21 +08:00
parent f36416a76c
commit c218b5cc8a
2 changed files with 59 additions and 41 deletions

View file

@ -1,6 +1,7 @@
import { logger, patcher } from "@vendetta"; import { logger, patcher, plugin } from "@vendetta";
import { findByProps, findByStoreName } from '@vendetta/metro'; import { findByProps, findByStoreName } from '@vendetta/metro';
import { FluxDispatcher } from '@vendetta/metro/common'; import { FluxDispatcher } from '@vendetta/metro/common';
import Settings from "./settings";
let stopped: Boolean, let stopped: Boolean,
lastActivity: Activity, lastActivity: Activity,
@ -8,13 +9,14 @@ let stopped: Boolean,
lastTrackUrl: string, lastTrackUrl: string,
activityTypeUnpatch: () => void; activityTypeUnpatch: () => void;
// These are hardcoded for now until settings panel is implemented const settings = plugin.storage as {
const appName = "Music"; appName: string;
const username = "slyde99"; username: string;
const showTimestamp = true; showTimestamp: string;
const timeInterval = 5000; timeInterval: number;
const listeningTo = true; listeningTo: boolean;
const verboseLogging = true; verboseLogging: boolean;
};
// Constants for the API calls (perhaps these should be options?) // Constants for the API calls (perhaps these should be options?)
const APPLICATION_ID = "1054951789318909972"; const APPLICATION_ID = "1054951789318909972";
@ -75,39 +77,30 @@ type Track = {
const UserStore = findByStoreName("UserStore") const UserStore = findByStoreName("UserStore")
const SET_ACTIVITY = findByProps('SET_ACTIVITY').SET_ACTIVITY; const SET_ACTIVITY = findByProps('SET_ACTIVITY').SET_ACTIVITY;
const verboseLog = (...message: any) => verboseLogging && logger.log(...message); const verboseLog = (...message: any) => settings.verboseLogging && logger.log(...message);
async function fetchCurrentScrobble(): Promise<Track> { async function fetchCurrentScrobble(): Promise<Track> {
const params = new URLSearchParams({ const params = new URLSearchParams({
'method': 'user.getrecenttracks', 'method': 'user.getrecenttracks',
'user': username, 'user': settings.username,
'api_key': LFM_API_KEY, 'api_key': LFM_API_KEY,
'format': 'json', 'format': 'json',
'limit': '1', 'limit': '1',
'extended': '1' 'extended': '1'
}).toString(); }).toString();
try { const info = await fetch(`https://ws.audioscrobbler.com/2.0/?${params}`).then(x => x.json());
const { const lastTrack = info.recenttracks?.track?.[0] || Promise.reject(info);
recenttracks: { return {
track: [lastTrack] name: lastTrack.name,
} artist: lastTrack.artist.name,
} = await fetch(`https://ws.audioscrobbler.com/2.0/?${params}`).then(x => x.json()); album: lastTrack.album['#text'],
albumArt: filterAlbumCover(lastTrack.image[3]['#text']),
return { url: lastTrack.url,
name: lastTrack.name, date: lastTrack.date?.['#text'] ?? 'now',
artist: lastTrack.artist.name, nowPlaying: Boolean(lastTrack['@attr']?.nowplaying),
album: lastTrack.album['#text'], loved: lastTrack.loved === '1',
albumArt: filterAlbumCover(lastTrack.image[3]['#text']), } as Track;
url: lastTrack.url,
date: lastTrack.date?.['#text'] ?? 'now',
nowPlaying: Boolean(lastTrack['@attr']?.nowplaying),
loved: lastTrack.loved === '1',
} as Track;
} catch (error) {
logger.error("Last.fm: An error occured while fetching user's track:\n", error);
throw error;
}
} }
// Currently ditches the default album covers (they're ugly) // Currently ditches the default album covers (they're ugly)
@ -121,6 +114,7 @@ function filterAlbumCover(cover: string): string {
// Clears the activity // Clears the activity
function clearActivity(): Promise<ResultActivity> { function clearActivity(): Promise<ResultActivity> {
lastActivity && verboseLog("--> Clearing activity...");
return sendRequest(null); return sendRequest(null);
} }
@ -155,7 +149,10 @@ async function sendRequest(activity: Activity): Promise<ResultActivity> {
// This is the main function that is called every 5 seconds (or whatever the user has set) // This is the main function that is called every 5 seconds (or whatever the user has set)
async function update() { async function update() {
verboseLog("--> Fetching last track..."); verboseLog("--> Fetching last track...");
const lastTrack = await fetchCurrentScrobble(); const lastTrack = await fetchCurrentScrobble().catch((err) => {
verboseLog("--> An error occurred while fetching the last track, aborting...");
throw err;
});
if (!lastTrack.nowPlaying) { if (!lastTrack.nowPlaying) {
verboseLog("--> Last track is not currently playing, aborting..."); verboseLog("--> Last track is not currently playing, aborting...");
@ -170,15 +167,15 @@ async function update() {
} }
const activity = { const activity = {
name: appName || "Music", name: settings.appName || "Music",
type: listeningTo ? 2 : 0, type: settings.listeningTo ? 2 : 0,
details: lastTrack.name, details: lastTrack.name,
state: `by ${lastTrack.artist}`, state: `by ${lastTrack.artist}`,
} as Activity; } as Activity;
lastTrackUrl = lastTrack.url; lastTrackUrl = lastTrack.url;
if (showTimestamp) { if (settings.showTimestamp) {
activity.timestamps = { activity.timestamps = {
start: Date.now() / 1000 | 0 start: Date.now() / 1000 | 0
}; };
@ -191,7 +188,10 @@ async function update() {
} }
} }
const response = await sendRequest(activity); const response = await sendRequest(activity).catch((err) => {
verboseLog("--> An error occurred while setting the activity");
throw err;
});
verboseLog("--> Successfully set activity!"); verboseLog("--> Successfully set activity!");
verboseLog(response); verboseLog(response);
@ -225,7 +225,7 @@ async function initialize() {
clearInterval(updateInterval); clearInterval(updateInterval);
} }
}), }),
timeInterval settings.timeInterval
); );
} }
@ -242,9 +242,9 @@ function patchActivityType() {
const { actionHandler } = nodes.find((x: any) => x.name === "LocalActivityStore") as any; const { actionHandler } = nodes.find((x: any) => x.name === "LocalActivityStore") as any;
activityTypeUnpatch = patcher.before("LOCAL_ACTIVITY_UPDATE", actionHandler, ([{ activity }]) => { activityTypeUnpatch = patcher.before("LOCAL_ACTIVITY_UPDATE", actionHandler, ([{ activity }]) => {
if (activity.name !== lastActivity.name) return; if (activity.name === lastActivity.name) {
activity.type = lastActivity.type;
activity.type = lastActivity.type; }
}); });
} }
@ -254,6 +254,14 @@ export default {
console.log("Starting last.fm plugin.."); console.log("Starting last.fm plugin..");
patchActivityType(); patchActivityType();
// Options
// settings.appName = "Music";
// settings.username = "slyde99";
// settings.showTimestamp = true;
// settings.timeInterval = 5000;
// settings.listeningTo = true;
// settings.verboseLogging = false;
// If the user is already logged in (brrr connection), initialize the plugin // If the user is already logged in (brrr connection), initialize the plugin
if (UserStore.getCurrentUser()) { if (UserStore.getCurrentUser()) {
console.log("User is already logged in, initializing..."); console.log("User is already logged in, initializing...");
@ -275,5 +283,6 @@ export default {
clearActivity(); clearActivity();
activityTypeUnpatch?.(); activityTypeUnpatch?.();
activityTypeUnpatch = null; activityTypeUnpatch = null;
} },
settings: Settings
} }

View file

@ -0,0 +1,9 @@
import { React, ReactNative } from "@vendetta/metro/common";
export default function Settings() {
return (
<ReactNative.Text>
Hello World!
</ReactNative.Text>
)
}