Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion plugins/DiscordRPC/src/Settings.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { LunaSettings, LunaSwitchSetting, LunaTextSetting } from "@luna/ui";
import { LunaSettings, LunaSwitchSetting, LunaTextSetting, LunaSelectSetting, LunaSelectItem } from "@luna/ui";

import { ReactiveStore } from "@luna/core";

import React from "react";
import { errSignal, trace } from ".";
import { updateActivity } from "./updateActivity";
import { getAvailablePipes } from "./getAvailablePipes.native";

const defaultCustomStatusText = "{track} by {artist}";

Expand All @@ -13,18 +14,52 @@ export const settings = await ReactiveStore.getPluginStorage("DiscordRPC", {
displayArtistIcon: true,
displayPlaylistButton: true,
customStatusText: defaultCustomStatusText,
pipeId: -1,
});

if (!settings.customStatusText || settings.customStatusText === "") settings.customStatusText = defaultCustomStatusText;
if (settings.pipeId === undefined) settings.pipeId = -1;

export const Settings = () => {
const [displayOnPause, setDisplayOnPause] = React.useState(settings.displayOnPause);
const [displayArtistIcon, setDisplayArtistIcon] = React.useState(settings.displayArtistIcon);
const [displayPlaylistButton, setDisplayPlaylistButton] = React.useState(settings.displayPlaylistButton);
const [customStatusText, setCustomStatusText] = React.useState(settings.customStatusText);

const [pipeId, setPipeId] = React.useState(settings.pipeId);
const [availablePipes, setAvailablePipes] = React.useState<number[]>([]);

React.useEffect(() => {
getAvailablePipes().then((pipes) => {
setAvailablePipes(pipes);
if (pipes.length > 0 && !pipes.includes(settings.pipeId)) {
setPipeId((settings.pipeId = pipes[0]));
updateActivity().catch(() => {});
}
}).catch(() => {});
}, []);

return (
<LunaSettings>
{availablePipes.length > 1 && (
<LunaSelectSetting
title="Discord Instance (Pipe ID)"
desc="Select which Discord instance to connect to."
value={pipeId.toString()}
onChange={(e) => {
setPipeId((settings.pipeId = parseInt(e.target.value, 10)));
updateActivity()
.then(() => (errSignal!._ = undefined))
.catch(trace.err.withContext("Failed to set activity"));
}}
>
{availablePipes.map((pipe) => (
<LunaSelectItem key={pipe} value={pipe.toString()}>
Pipe {pipe}
</LunaSelectItem>
))}
</LunaSelectSetting>
)}
<LunaSwitchSetting
title="Display activity when paused"
desc="If disabled, when paused discord wont show the activity"
Expand Down
46 changes: 36 additions & 10 deletions plugins/DiscordRPC/src/discord.native.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
import { Client, StatusDisplayType, type SetActivity } from "@xhayper/discord-rpc";
import { Client, StatusDisplayType, type ClientOptions, type SetActivity } from "@xhayper/discord-rpc";
import { asyncDebounce } from "@inrixia/helpers";
import { getAvailablePipes } from "./getAvailablePipes.native";

let rpcClient: Client | null = null;
export const getClient = async () => {
let currentPipeId: number = -1;

export const getClient = asyncDebounce(async (preferredPipeId: number = -1) => {
const availablePipes = await getAvailablePipes();

let targetPipe = preferredPipeId;
if (availablePipes.length > 0) {
targetPipe = availablePipes.includes(preferredPipeId) ? preferredPipeId : availablePipes[0];
}

if (rpcClient && currentPipeId !== targetPipe) {
await rpcClient.destroy();
}

const isAvailable = rpcClient && rpcClient.transport.isConnected && rpcClient.user;
if (isAvailable) return rpcClient!;

if (rpcClient) await rpcClient.destroy();
rpcClient = new Client({ clientId: "1130698654987067493" });
await rpcClient.connect();

const clientOptions: ClientOptions = {
clientId: "1130698654987067493"
};

if (targetPipe >= 0) {
clientOptions.pipeId = targetPipe;
}

rpcClient = new Client(clientOptions);
currentPipeId = targetPipe;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should only be set after .connect is called

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only this left and then happy to merge, thanks for fixing these things 💜


await rpcClient.connect();
return rpcClient;
};
});

export const setActivity = async (activity?: SetActivity) => {
const client = await getClient();
if (!client.user) return;
export const setActivity = async (activity?: SetActivity, preferredPipeId: number = -1) => {
const client = await getClient(preferredPipeId);
if (!client?.user) return;
if (!activity) return client.user.clearActivity();
return client.user.setActivity(activity);
return await client.user.setActivity(activity);
};

export const cleanupRPC = () => rpcClient?.destroy()!;
export const cleanupRPC = () => rpcClient?.destroy();

export const StatusDisplayTypeEnum = () => ({
Name: StatusDisplayType.NAME,
State: StatusDisplayType.STATE,
Expand Down
29 changes: 29 additions & 0 deletions plugins/DiscordRPC/src/getAvailablePipes.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { readdir } from "node:fs/promises";
import { tmpdir } from "node:os";

export const getAvailablePipes = async (): Promise<number[]> => {
const pipes = new Set<number>();
try {
if (process.platform === "win32") {
const files = await readdir("\\\\.\\pipe\\");
for (const file of files) {
if (file.startsWith("discord-ipc-")) {
const id = parseInt(file.replace("discord-ipc-", ""), 10);
if (!isNaN(id)) pipes.add(id);
}
}
} else {
const tempDir = process.env.XDG_RUNTIME_DIR ?? tmpdir();
const files = await readdir(tempDir);
for (const file of files) {
if (file.startsWith("discord-ipc-")) {
const id = parseInt(file.replace("discord-ipc-", ""), 10);
if (!isNaN(id)) pipes.add(id);
}
}
}
} catch {
// Ignore read errors
}
return Array.from(pipes).sort((a, b) => a - b);
};
4 changes: 2 additions & 2 deletions plugins/DiscordRPC/src/updateActivity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { settings } from "./Settings";
const StatusDisplayType = await StatusDisplayTypeEnum();

export const updateActivity = async (mediaItem?: MediaItem) => {
if (!PlayState.playing && !settings.displayOnPause) return await setActivity();
if (!PlayState.playing && !settings.displayOnPause) return await setActivity(undefined, settings.pipeId);

mediaItem ??= await MediaItem.fromPlaybackContext();
if (mediaItem === undefined) return;
Expand Down Expand Up @@ -83,5 +83,5 @@ export const updateActivity = async (mediaItem?: MediaItem) => {
activity.largeImageUrl = `https://tidal.com/album/${album.id}/u`;
}

await setActivity(activity);
await setActivity(activity, settings.pipeId);
};