2025-09-13 00:12:49 +02:00
|
|
|
import { plugin } from "@vendetta";
|
2025-09-13 22:10:01 +02:00
|
|
|
import { FluxDispatcher } from "@vendetta/metro/common";
|
|
|
|
|
import { getAssetIDByName } from "@vendetta/ui/assets";
|
|
|
|
|
import { showToast } from "@vendetta/ui/toasts";
|
2025-09-13 22:16:11 +02:00
|
|
|
import { React } from "@vendetta/metro/common";
|
2025-09-19 21:39:56 +02:00
|
|
|
import { ScrollView, View } from "react-native";
|
2025-09-13 22:16:11 +02:00
|
|
|
import { Forms } from "@vendetta/ui/components";
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
import { lazy } from "react";
|
|
|
|
|
import { LFMSettings } from "../../defs";
|
|
|
|
|
import Constants from "./constants";
|
|
|
|
|
import { initialize, stop } from "./manager";
|
2025-09-13 00:12:49 +02:00
|
|
|
import { UserStore } from "./modules";
|
|
|
|
|
|
2025-09-13 22:16:11 +02:00
|
|
|
const { FormText } = Forms;
|
|
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
export const pluginState = {
|
|
|
|
|
pluginStopped: false,
|
|
|
|
|
lastActivity: undefined,
|
|
|
|
|
updateInterval: undefined,
|
|
|
|
|
lastTrackUrl: undefined,
|
|
|
|
|
} as {
|
|
|
|
|
pluginStopped: boolean;
|
|
|
|
|
lastActivity?: any;
|
|
|
|
|
updateInterval?: NodeJS.Timer;
|
|
|
|
|
lastTrackUrl?: string;
|
|
|
|
|
};
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
// Initialize default settings
|
|
|
|
|
const defaultSettings: LFMSettings = Constants.DEFAULT_SETTINGS;
|
|
|
|
|
for (const key in defaultSettings) {
|
|
|
|
|
plugin.storage[key] =
|
|
|
|
|
plugin.storage[key] ?? defaultSettings[key as keyof typeof defaultSettings];
|
|
|
|
|
}
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
export const currentSettings = new Proxy(plugin.storage, {
|
|
|
|
|
get(target, prop) {
|
|
|
|
|
return target[prop];
|
|
|
|
|
},
|
|
|
|
|
set(target, prop, value) {
|
|
|
|
|
target[prop] = value;
|
|
|
|
|
return true;
|
|
|
|
|
},
|
|
|
|
|
});
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-19 21:50:49 +02:00
|
|
|
// Simple Settings component for fallback
|
|
|
|
|
function FallbackSettings() {
|
|
|
|
|
return (
|
|
|
|
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
|
|
|
|
|
<FormText style={{ color: "#ED4245" }}>
|
|
|
|
|
Failed to load Last.fm settings. Please check your connection and reload
|
|
|
|
|
Discord.
|
|
|
|
|
</FormText>
|
|
|
|
|
</ScrollView>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-13 22:22:13 +02:00
|
|
|
// Settings component with error handling
|
2025-09-19 21:50:49 +02:00
|
|
|
const Settings = lazy(async () => {
|
|
|
|
|
try {
|
|
|
|
|
const module = await import("./ui/pages/Settings");
|
|
|
|
|
return { default: module.default || FallbackSettings };
|
|
|
|
|
} catch (err) {
|
|
|
|
|
console.error("[Last.fm] Failed to load settings:", err);
|
|
|
|
|
return { default: FallbackSettings };
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
// Connection status tracking
|
|
|
|
|
let connectionAttempts = 0;
|
|
|
|
|
const MAX_CONNECTION_ATTEMPTS = 3;
|
|
|
|
|
const RECONNECT_DELAY = 5000;
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
async function tryInitialize() {
|
|
|
|
|
try {
|
|
|
|
|
await initialize();
|
|
|
|
|
connectionAttempts = 0;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("[Last.fm] Initialization error:", error);
|
|
|
|
|
connectionAttempts++;
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
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"));
|
2025-09-13 00:12:49 +02:00
|
|
|
}
|
2025-09-13 22:10:01 +02:00
|
|
|
}
|
2025-09-13 00:12:49 +02:00
|
|
|
}
|
|
|
|
|
|
2025-09-19 21:50:49 +02:00
|
|
|
// Create the plugin object
|
|
|
|
|
const pluginObj = {
|
2025-09-13 22:10:01 +02:00
|
|
|
onLoad() {
|
|
|
|
|
pluginState.pluginStopped = false;
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
if (!currentSettings.username || !currentSettings.apiKey) {
|
|
|
|
|
showToast(
|
|
|
|
|
"Please configure Last.fm username and API key in settings",
|
|
|
|
|
getAssetIDByName("ic_warning"),
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
if (UserStore.getCurrentUser()) {
|
|
|
|
|
tryInitialize();
|
|
|
|
|
} else {
|
|
|
|
|
const waitForUser = () => {
|
|
|
|
|
if (UserStore.getCurrentUser()) {
|
|
|
|
|
tryInitialize();
|
|
|
|
|
FluxDispatcher.unsubscribe("CONNECTION_OPEN", waitForUser);
|
2025-09-13 00:12:49 +02:00
|
|
|
}
|
2025-09-13 22:10:01 +02:00
|
|
|
};
|
2025-09-13 00:12:49 +02:00
|
|
|
|
2025-09-13 22:10:01 +02:00
|
|
|
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();
|
2025-09-13 00:12:49 +02:00
|
|
|
}
|
2025-09-13 22:10:01 +02:00
|
|
|
},
|
2025-09-13 00:12:49 +02:00
|
|
|
};
|
2025-09-19 21:50:49 +02:00
|
|
|
|
|
|
|
|
// Add settings property to the plugin object
|
|
|
|
|
Object.defineProperty(pluginObj, "settings", {
|
|
|
|
|
get: () => (
|
|
|
|
|
<React.Suspense
|
|
|
|
|
fallback={
|
|
|
|
|
<View
|
|
|
|
|
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
|
|
|
|
|
>
|
|
|
|
|
<FormText>Loading Last.fm settings...</FormText>
|
|
|
|
|
</View>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<Settings />
|
|
|
|
|
</React.Suspense>
|
|
|
|
|
),
|
|
|
|
|
enumerable: true,
|
|
|
|
|
configurable: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export default pluginObj;
|