···11-# Pipris 
11+# Pipris 
2233Pipris is an extensible MPRIS scrobbler written with Deno. It was originally created for
44[teal.fm](https://teal.fm), but can be extended to support a wide variety of
+40-3
src/modules/discord.js
···1010let client;
1111let config;
1212let lastArtUrl = null;
1313+let lastData = null;
1414+let intentionallyClosed = false;
1515+let reconnectTimer = null;
13161417// Cache: local file path → { url, uploadedAt }
1518const artCache = new Map();
···5659 }
5760}
58616262+async function connect() {
6363+ client = new RPCClient(config.clientId, false);
6464+ await client.init();
6565+ console.log("[discord] Connected to Discord RPC");
6666+}
6767+6868+function scheduleReconnect(delayMs = 5000) {
6969+ if (intentionallyClosed || reconnectTimer) return;
7070+ console.log(`[discord] Scheduling reconnect in ${delayMs / 1000}s...`);
7171+ reconnectTimer = setTimeout(async () => {
7272+ reconnectTimer = null;
7373+ if (intentionallyClosed) return;
7474+ try {
7575+ await connect();
7676+ console.log("[discord] Reconnected to Discord RPC");
7777+ if (lastData) {
7878+ await onData(lastData);
7979+ }
8080+ } catch (err) {
8181+ console.error(`[discord] Reconnect failed: ${err.message}`);
8282+ scheduleReconnect(Math.min(delayMs * 2, 60000));
8383+ }
8484+ }, delayMs);
8585+}
8686+5987export async function init(cfg) {
6088 if (!cfg || !cfg.clientId) {
6189 throw new Error("Missing config/discord.json (needs clientId)");
6290 }
6391 config = cfg;
9292+ intentionallyClosed = false;
64936565- client = new RPCClient(config.clientId, false);
6666- await client.init();
6767- console.log("[discord] Connected to Discord RPC");
9494+ await connect();
6895}
69967097export async function onData(data) {
7198 if (!client) return;
9999+ lastData = data;
7210073101 const artistString = data.artists.map((a) => a.artistName).join(", ");
74102 const paused = data.playbackStatus !== "Playing";
···125153 client.setActivity(buildActivity(cachedUrl, false));
126154 } catch (err) {
127155 console.error(`[discord] Failed to set activity: ${err.message}`);
156156+ client = null;
157157+ scheduleReconnect();
158158+ return;
128159 }
129160130161 // If artUrl is a local file and wasn't cached, upload in background and update
···144175}
145176146177export function onClear() {
178178+ intentionallyClosed = true;
179179+ lastData = null;
180180+ if (reconnectTimer) {
181181+ clearTimeout(reconnectTimer);
182182+ reconnectTimer = null;
183183+ }
147184 if (!client) return;
148185 try {
149186 client.close();