/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // (disabled):register-scheme var require_register_scheme = __commonJS({ "(disabled):register-scheme"() { } }); // node_modules/discord-rpc/src/util.js var require_util = __commonJS({ "node_modules/discord-rpc/src/util.js"(exports, module2) { "use strict"; var register; try { const { app } = require("electron"); register = app.setAsDefaultProtocolClient.bind(app); } catch (err) { try { register = require_register_scheme(); } catch (e) { } } if (typeof register !== "function") { register = () => false; } function pid() { if (typeof process !== "undefined") { return process.pid; } return null; } var uuid4122 = () => { let uuid = ""; for (let i = 0; i < 32; i += 1) { if (i === 8 || i === 12 || i === 16 || i === 20) { uuid += "-"; } let n; if (i === 12) { n = 4; } else { const random = Math.random() * 16 | 0; if (i === 16) { n = random & 3 | 0; } else { n = random; } } uuid += n.toString(16); } return uuid; }; module2.exports = { pid, register, uuid: uuid4122 }; } }); // node_modules/node-fetch/browser.js var require_browser = __commonJS({ "node_modules/node-fetch/browser.js"(exports, module2) { "use strict"; var getGlobal = function() { if (typeof self !== "undefined") { return self; } if (typeof window !== "undefined") { return window; } if (typeof global !== "undefined") { return global; } throw new Error("unable to locate global object"); }; var globalObject = getGlobal(); module2.exports = exports = globalObject.fetch; if (globalObject.fetch) { exports.default = globalObject.fetch.bind(globalObject); } exports.Headers = globalObject.Headers; exports.Request = globalObject.Request; exports.Response = globalObject.Response; } }); // node_modules/discord-rpc/src/transports/ipc.js var require_ipc = __commonJS({ "node_modules/discord-rpc/src/transports/ipc.js"(exports, module2) { "use strict"; var net = require("net"); var EventEmitter = require("events"); var fetch = require_browser(); var { uuid } = require_util(); var OPCodes = { HANDSHAKE: 0, FRAME: 1, CLOSE: 2, PING: 3, PONG: 4 }; function getIPCPath(id) { if (process.platform === "win32") { return `\\\\?\\pipe\\discord-ipc-${id}`; } const { env: { XDG_RUNTIME_DIR, TMPDIR, TMP, TEMP } } = process; const prefix = XDG_RUNTIME_DIR || TMPDIR || TMP || TEMP || "/tmp"; return `${prefix.replace(/\/$/, "")}/discord-ipc-${id}`; } function getIPC(id = 0) { return new Promise((resolve, reject) => { const path = getIPCPath(id); const onerror = () => { if (id < 10) { resolve(getIPC(id + 1)); } else { reject(new Error("Could not connect")); } }; const sock = net.createConnection(path, () => { sock.removeListener("error", onerror); resolve(sock); }); sock.once("error", onerror); }); } async function findEndpoint(tries = 0) { if (tries > 30) { throw new Error("Could not find endpoint"); } const endpoint = `http://127.0.0.1:${6463 + tries % 10}`; try { const r = await fetch(endpoint); if (r.status === 404) { return endpoint; } return findEndpoint(tries + 1); } catch (e) { return findEndpoint(tries + 1); } } function encode(op, data) { data = JSON.stringify(data); const len = Buffer.byteLength(data); const packet = Buffer.alloc(8 + len); packet.writeInt32LE(op, 0); packet.writeInt32LE(len, 4); packet.write(data, 8, len); return packet; } var working = { full: "", op: void 0 }; function decode(socket, callback) { const packet = socket.read(); if (!packet) { return; } let { op } = working; let raw; if (working.full === "") { op = working.op = packet.readInt32LE(0); const len = packet.readInt32LE(4); raw = packet.slice(8, len + 8); } else { raw = packet.toString(); } try { const data = JSON.parse(working.full + raw); callback({ op, data }); working.full = ""; working.op = void 0; } catch (err) { working.full += raw; } decode(socket, callback); } var IPCTransport = class extends EventEmitter { constructor(client) { super(); this.client = client; this.socket = null; } async connect() { const socket = this.socket = await getIPC(); socket.on("close", this.onClose.bind(this)); socket.on("error", this.onClose.bind(this)); this.emit("open"); socket.write(encode(OPCodes.HANDSHAKE, { v: 1, client_id: this.client.clientId })); socket.pause(); socket.on("readable", () => { decode(socket, ({ op, data }) => { switch (op) { case OPCodes.PING: this.send(data, OPCodes.PONG); break; case OPCodes.FRAME: if (!data) { return; } if (data.cmd === "AUTHORIZE" && data.evt !== "ERROR") { findEndpoint().then((endpoint) => { this.client.request.endpoint = endpoint; }).catch((e) => { this.client.emit("error", e); }); } this.emit("message", data); break; case OPCodes.CLOSE: this.emit("close", data); break; default: break; } }); }); } onClose(e) { this.emit("close", e); } send(data, op = OPCodes.FRAME) { this.socket.write(encode(op, data)); } async close() { return new Promise((r) => { this.once("close", r); this.send({}, OPCodes.CLOSE); this.socket.end(); }); } ping() { this.send(uuid(), OPCodes.PING); } }; module2.exports = IPCTransport; module2.exports.encode = encode; module2.exports.decode = decode; } }); // node_modules/discord-rpc/src/constants.js var require_constants = __commonJS({ "node_modules/discord-rpc/src/constants.js"(exports) { "use strict"; function keyMirror(arr) { const tmp = {}; for (const value of arr) { tmp[value] = value; } return tmp; } exports.browser = typeof window !== "undefined"; exports.RPCCommands = keyMirror([ "DISPATCH", "AUTHORIZE", "AUTHENTICATE", "GET_GUILD", "GET_GUILDS", "GET_CHANNEL", "GET_CHANNELS", "CREATE_CHANNEL_INVITE", "GET_RELATIONSHIPS", "GET_USER", "SUBSCRIBE", "UNSUBSCRIBE", "SET_USER_VOICE_SETTINGS", "SET_USER_VOICE_SETTINGS_2", "SELECT_VOICE_CHANNEL", "GET_SELECTED_VOICE_CHANNEL", "SELECT_TEXT_CHANNEL", "GET_VOICE_SETTINGS", "SET_VOICE_SETTINGS_2", "SET_VOICE_SETTINGS", "CAPTURE_SHORTCUT", "SET_ACTIVITY", "SEND_ACTIVITY_JOIN_INVITE", "CLOSE_ACTIVITY_JOIN_REQUEST", "ACTIVITY_INVITE_USER", "ACCEPT_ACTIVITY_INVITE", "INVITE_BROWSER", "DEEP_LINK", "CONNECTIONS_CALLBACK", "BRAINTREE_POPUP_BRIDGE_CALLBACK", "GIFT_CODE_BROWSER", "GUILD_TEMPLATE_BROWSER", "OVERLAY", "BROWSER_HANDOFF", "SET_CERTIFIED_DEVICES", "GET_IMAGE", "CREATE_LOBBY", "UPDATE_LOBBY", "DELETE_LOBBY", "UPDATE_LOBBY_MEMBER", "CONNECT_TO_LOBBY", "DISCONNECT_FROM_LOBBY", "SEND_TO_LOBBY", "SEARCH_LOBBIES", "CONNECT_TO_LOBBY_VOICE", "DISCONNECT_FROM_LOBBY_VOICE", "SET_OVERLAY_LOCKED", "OPEN_OVERLAY_ACTIVITY_INVITE", "OPEN_OVERLAY_GUILD_INVITE", "OPEN_OVERLAY_VOICE_SETTINGS", "VALIDATE_APPLICATION", "GET_ENTITLEMENT_TICKET", "GET_APPLICATION_TICKET", "START_PURCHASE", "GET_SKUS", "GET_ENTITLEMENTS", "GET_NETWORKING_CONFIG", "NETWORKING_SYSTEM_METRICS", "NETWORKING_PEER_METRICS", "NETWORKING_CREATE_TOKEN", "SET_USER_ACHIEVEMENT", "GET_USER_ACHIEVEMENTS" ]); exports.RPCEvents = keyMirror([ "CURRENT_USER_UPDATE", "GUILD_STATUS", "GUILD_CREATE", "CHANNEL_CREATE", "RELATIONSHIP_UPDATE", "VOICE_CHANNEL_SELECT", "VOICE_STATE_CREATE", "VOICE_STATE_DELETE", "VOICE_STATE_UPDATE", "VOICE_SETTINGS_UPDATE", "VOICE_SETTINGS_UPDATE_2", "VOICE_CONNECTION_STATUS", "SPEAKING_START", "SPEAKING_STOP", "GAME_JOIN", "GAME_SPECTATE", "ACTIVITY_JOIN", "ACTIVITY_JOIN_REQUEST", "ACTIVITY_SPECTATE", "ACTIVITY_INVITE", "NOTIFICATION_CREATE", "MESSAGE_CREATE", "MESSAGE_UPDATE", "MESSAGE_DELETE", "LOBBY_DELETE", "LOBBY_UPDATE", "LOBBY_MEMBER_CONNECT", "LOBBY_MEMBER_DISCONNECT", "LOBBY_MEMBER_UPDATE", "LOBBY_MESSAGE", "CAPTURE_SHORTCUT_CHANGE", "OVERLAY", "OVERLAY_UPDATE", "ENTITLEMENT_CREATE", "ENTITLEMENT_DELETE", "USER_ACHIEVEMENT_UPDATE", "READY", "ERROR" ]); exports.RPCErrors = { CAPTURE_SHORTCUT_ALREADY_LISTENING: 5004, GET_GUILD_TIMED_OUT: 5002, INVALID_ACTIVITY_JOIN_REQUEST: 4012, INVALID_ACTIVITY_SECRET: 5005, INVALID_CHANNEL: 4005, INVALID_CLIENTID: 4007, INVALID_COMMAND: 4002, INVALID_ENTITLEMENT: 4015, INVALID_EVENT: 4004, INVALID_GIFT_CODE: 4016, INVALID_GUILD: 4003, INVALID_INVITE: 4011, INVALID_LOBBY: 4013, INVALID_LOBBY_SECRET: 4014, INVALID_ORIGIN: 4008, INVALID_PAYLOAD: 4e3, INVALID_PERMISSIONS: 4006, INVALID_TOKEN: 4009, INVALID_USER: 4010, LOBBY_FULL: 5007, NO_ELIGIBLE_ACTIVITY: 5006, OAUTH2_ERROR: 5e3, PURCHASE_CANCELED: 5008, PURCHASE_ERROR: 5009, RATE_LIMITED: 5011, SELECT_CHANNEL_TIMED_OUT: 5001, SELECT_VOICE_FORCE_REQUIRED: 5003, SERVICE_UNAVAILABLE: 1001, TRANSACTION_ABORTED: 1002, UNAUTHORIZED_FOR_ACHIEVEMENT: 5010, UNKNOWN_ERROR: 1e3 }; exports.RPCCloseCodes = { CLOSE_NORMAL: 1e3, CLOSE_UNSUPPORTED: 1003, CLOSE_ABNORMAL: 1006, INVALID_CLIENTID: 4e3, INVALID_ORIGIN: 4001, RATELIMITED: 4002, TOKEN_REVOKED: 4003, INVALID_VERSION: 4004, INVALID_ENCODING: 4005 }; exports.LobbyTypes = { PRIVATE: 1, PUBLIC: 2 }; exports.RelationshipTypes = { NONE: 0, FRIEND: 1, BLOCKED: 2, PENDING_INCOMING: 3, PENDING_OUTGOING: 4, IMPLICIT: 5 }; } }); // (disabled):node_modules/ws/browser.js var require_browser2 = __commonJS({ "(disabled):node_modules/ws/browser.js"() { } }); // node_modules/discord-rpc/src/transports/websocket.js var require_websocket = __commonJS({ "node_modules/discord-rpc/src/transports/websocket.js"(exports, module2) { "use strict"; var EventEmitter = require("events"); var { browser } = require_constants(); var WebSocket = browser ? window.WebSocket : require_browser2(); var pack = (d) => JSON.stringify(d); var unpack = (s) => JSON.parse(s); var WebSocketTransport = class extends EventEmitter { constructor(client) { super(); this.client = client; this.ws = null; this.tries = 0; } async connect() { const port = 6463 + this.tries % 10; this.tries += 1; this.ws = new WebSocket( `ws://127.0.0.1:${port}/?v=1&client_id=${this.client.clientId}`, browser ? void 0 : { origin: this.client.options.origin } ); this.ws.onopen = this.onOpen.bind(this); this.ws.onclose = this.onClose.bind(this); this.ws.onerror = this.onError.bind(this); this.ws.onmessage = this.onMessage.bind(this); } onOpen() { this.emit("open"); } onClose(event) { if (!event.wasClean) { return; } this.emit("close", event); } onError(event) { try { this.ws.close(); } catch (e) { } if (this.tries > 20) { this.emit("error", event.error); } else { setTimeout(() => { this.connect(); }, 250); } } onMessage(event) { this.emit("message", unpack(event.data)); } send(data) { this.ws.send(pack(data)); } ping() { } // eslint-disable-line no-empty-function close() { return new Promise((r) => { this.once("close", r); this.ws.close(); }); } }; module2.exports = WebSocketTransport; } }); // node_modules/discord-rpc/src/transports/index.js var require_transports = __commonJS({ "node_modules/discord-rpc/src/transports/index.js"(exports, module2) { "use strict"; module2.exports = { ipc: require_ipc(), websocket: require_websocket() }; } }); // node_modules/discord-rpc/src/client.js var require_client = __commonJS({ "node_modules/discord-rpc/src/client.js"(exports, module2) { "use strict"; var EventEmitter = require("events"); var { setTimeout: setTimeout2, clearTimeout } = require("timers"); var fetch = require_browser(); var transports = require_transports(); var { RPCCommands, RPCEvents, RelationshipTypes } = require_constants(); var { pid: getPid, uuid } = require_util(); function subKey(event, args) { return `${event}${JSON.stringify(args)}`; } var RPCClient = class extends EventEmitter { /** * @param {RPCClientOptions} [options] Options for the client. * You must provide a transport */ constructor(options = {}) { super(); this.options = options; this.accessToken = null; this.clientId = null; this.application = null; this.user = null; const Transport = transports[options.transport]; if (!Transport) { throw new TypeError("RPC_INVALID_TRANSPORT", options.transport); } this.fetch = (method, path, { data, query } = {}) => fetch(`${this.fetch.endpoint}${path}${query ? new URLSearchParams(query) : ""}`, { method, body: data, headers: { Authorization: `Bearer ${this.accessToken}` } }).then(async (r) => { const body = await r.json(); if (!r.ok) { const e = new Error(r.status); e.body = body; throw e; } return body; }); this.fetch.endpoint = "https://discord.com/api"; this.transport = new Transport(this); this.transport.on("message", this._onRpcMessage.bind(this)); this._expecting = /* @__PURE__ */ new Map(); this._connectPromise = void 0; } /** * Search and connect to RPC */ connect(clientId) { if (this._connectPromise) { return this._connectPromise; } this._connectPromise = new Promise((resolve, reject) => { this.clientId = clientId; const timeout = setTimeout2(() => reject(new Error("RPC_CONNECTION_TIMEOUT")), 1e4); timeout.unref(); this.once("connected", () => { clearTimeout(timeout); resolve(this); }); this.transport.once("close", () => { this._expecting.forEach((e) => { e.reject(new Error("connection closed")); }); this.emit("disconnected"); reject(new Error("connection closed")); }); this.transport.connect().catch(reject); }); return this._connectPromise; } /** * @typedef {RPCLoginOptions} * @param {string} clientId Client ID * @param {string} [clientSecret] Client secret * @param {string} [accessToken] Access token * @param {string} [rpcToken] RPC token * @param {string} [tokenEndpoint] Token endpoint * @param {string[]} [scopes] Scopes to authorize with */ /** * Performs authentication flow. Automatically calls Client#connect if needed. * @param {RPCLoginOptions} options Options for authentication. * At least one property must be provided to perform login. * @example client.login({ clientId: '1234567', clientSecret: 'abcdef123' }); * @returns {Promise} */ async login(options = {}) { let { clientId, accessToken } = options; await this.connect(clientId); if (!options.scopes) { this.emit("ready"); return this; } if (!accessToken) { accessToken = await this.authorize(options); } return this.authenticate(accessToken); } /** * Request * @param {string} cmd Command * @param {Object} [args={}] Arguments * @param {string} [evt] Event * @returns {Promise} * @private */ request(cmd, args, evt) { return new Promise((resolve, reject) => { const nonce = uuid(); this.transport.send({ cmd, args, evt, nonce }); this._expecting.set(nonce, { resolve, reject }); }); } /** * Message handler * @param {Object} message message * @private */ _onRpcMessage(message) { if (message.cmd === RPCCommands.DISPATCH && message.evt === RPCEvents.READY) { if (message.data.user) { this.user = message.data.user; } this.emit("connected"); } else if (this._expecting.has(message.nonce)) { const { resolve, reject } = this._expecting.get(message.nonce); if (message.evt === "ERROR") { const e = new Error(message.data.message); e.code = message.data.code; e.data = message.data; reject(e); } else { resolve(message.data); } this._expecting.delete(message.nonce); } else { this.emit(message.evt, message.data); } } /** * Authorize * @param {Object} options options * @returns {Promise} * @private */ async authorize({ scopes, clientSecret, rpcToken, redirectUri, prompt } = {}) { if (clientSecret && rpcToken === true) { const body = await this.fetch("POST", "/oauth2/token/rpc", { data: new URLSearchParams({ client_id: this.clientId, client_secret: clientSecret }) }); rpcToken = body.rpc_token; } const { code } = await this.request("AUTHORIZE", { scopes, client_id: this.clientId, prompt, rpc_token: rpcToken }); const response = await this.fetch("POST", "/oauth2/token", { data: new URLSearchParams({ client_id: this.clientId, client_secret: clientSecret, code, grant_type: "authorization_code", redirect_uri: redirectUri }) }); return response.access_token; } /** * Authenticate * @param {string} accessToken access token * @returns {Promise} * @private */ authenticate(accessToken) { return this.request("AUTHENTICATE", { access_token: accessToken }).then(({ application, user }) => { this.accessToken = accessToken; this.application = application; this.user = user; this.emit("ready"); return this; }); } /** * Fetch a guild * @param {Snowflake} id Guild ID * @param {number} [timeout] Timeout request * @returns {Promise} */ getGuild(id, timeout) { return this.request(RPCCommands.GET_GUILD, { guild_id: id, timeout }); } /** * Fetch all guilds * @param {number} [timeout] Timeout request * @returns {Promise>} */ getGuilds(timeout) { return this.request(RPCCommands.GET_GUILDS, { timeout }); } /** * Get a channel * @param {Snowflake} id Channel ID * @param {number} [timeout] Timeout request * @returns {Promise} */ getChannel(id, timeout) { return this.request(RPCCommands.GET_CHANNEL, { channel_id: id, timeout }); } /** * Get all channels * @param {Snowflake} [id] Guild ID * @param {number} [timeout] Timeout request * @returns {Promise>} */ async getChannels(id, timeout) { const { channels } = await this.request(RPCCommands.GET_CHANNELS, { timeout, guild_id: id }); return channels; } /** * @typedef {CertifiedDevice} * @prop {string} type One of `AUDIO_INPUT`, `AUDIO_OUTPUT`, `VIDEO_INPUT` * @prop {string} uuid This device's Windows UUID * @prop {object} vendor Vendor information * @prop {string} vendor.name Vendor's name * @prop {string} vendor.url Vendor's url * @prop {object} model Model information * @prop {string} model.name Model's name * @prop {string} model.url Model's url * @prop {string[]} related Array of related product's Windows UUIDs * @prop {boolean} echoCancellation If the device has echo cancellation * @prop {boolean} noiseSuppression If the device has noise suppression * @prop {boolean} automaticGainControl If the device has automatic gain control * @prop {boolean} hardwareMute If the device has a hardware mute */ /** * Tell discord which devices are certified * @param {CertifiedDevice[]} devices Certified devices to send to discord * @returns {Promise} */ setCertifiedDevices(devices) { return this.request(RPCCommands.SET_CERTIFIED_DEVICES, { devices: devices.map((d) => ({ type: d.type, id: d.uuid, vendor: d.vendor, model: d.model, related: d.related, echo_cancellation: d.echoCancellation, noise_suppression: d.noiseSuppression, automatic_gain_control: d.automaticGainControl, hardware_mute: d.hardwareMute })) }); } /** * @typedef {UserVoiceSettings} * @prop {Snowflake} id ID of the user these settings apply to * @prop {?Object} [pan] Pan settings, an object with `left` and `right` set between * 0.0 and 1.0, inclusive * @prop {?number} [volume=100] The volume * @prop {bool} [mute] If the user is muted */ /** * Set the voice settings for a user, by id * @param {Snowflake} id ID of the user to set * @param {UserVoiceSettings} settings Settings * @returns {Promise} */ setUserVoiceSettings(id, settings) { return this.request(RPCCommands.SET_USER_VOICE_SETTINGS, { user_id: id, pan: settings.pan, mute: settings.mute, volume: settings.volume }); } /** * Move the user to a voice channel * @param {Snowflake} id ID of the voice channel * @param {Object} [options] Options * @param {number} [options.timeout] Timeout for the command * @param {boolean} [options.force] Force this move. This should only be done if you * have explicit permission from the user. * @returns {Promise} */ selectVoiceChannel(id, { timeout, force = false } = {}) { return this.request(RPCCommands.SELECT_VOICE_CHANNEL, { channel_id: id, timeout, force }); } /** * Move the user to a text channel * @param {Snowflake} id ID of the voice channel * @param {Object} [options] Options * @param {number} [options.timeout] Timeout for the command * have explicit permission from the user. * @returns {Promise} */ selectTextChannel(id, { timeout } = {}) { return this.request(RPCCommands.SELECT_TEXT_CHANNEL, { channel_id: id, timeout }); } /** * Get current voice settings * @returns {Promise} */ getVoiceSettings() { return this.request(RPCCommands.GET_VOICE_SETTINGS).then((s) => ({ automaticGainControl: s.automatic_gain_control, echoCancellation: s.echo_cancellation, noiseSuppression: s.noise_suppression, qos: s.qos, silenceWarning: s.silence_warning, deaf: s.deaf, mute: s.mute, input: { availableDevices: s.input.available_devices, device: s.input.device_id, volume: s.input.volume }, output: { availableDevices: s.output.available_devices, device: s.output.device_id, volume: s.output.volume }, mode: { type: s.mode.type, autoThreshold: s.mode.auto_threshold, threshold: s.mode.threshold, shortcut: s.mode.shortcut, delay: s.mode.delay } })); } /** * Set current voice settings, overriding the current settings until this session disconnects. * This also locks the settings for any other rpc sessions which may be connected. * @param {Object} args Settings * @returns {Promise} */ setVoiceSettings(args) { return this.request(RPCCommands.SET_VOICE_SETTINGS, { automatic_gain_control: args.automaticGainControl, echo_cancellation: args.echoCancellation, noise_suppression: args.noiseSuppression, qos: args.qos, silence_warning: args.silenceWarning, deaf: args.deaf, mute: args.mute, input: args.input ? { device_id: args.input.device, volume: args.input.volume } : void 0, output: args.output ? { device_id: args.output.device, volume: args.output.volume } : void 0, mode: args.mode ? { type: args.mode.type, auto_threshold: args.mode.autoThreshold, threshold: args.mode.threshold, shortcut: args.mode.shortcut, delay: args.mode.delay } : void 0 }); } /** * Capture a shortcut using the client * The callback takes (key, stop) where `stop` is a function that will stop capturing. * This `stop` function must be called before disconnecting or else the user will have * to restart their client. * @param {Function} callback Callback handling keys * @returns {Promise} */ captureShortcut(callback) { const subid = subKey(RPCEvents.CAPTURE_SHORTCUT_CHANGE); const stop = () => { this._subscriptions.delete(subid); return this.request(RPCCommands.CAPTURE_SHORTCUT, { action: "STOP" }); }; this._subscriptions.set(subid, ({ shortcut }) => { callback(shortcut, stop); }); return this.request(RPCCommands.CAPTURE_SHORTCUT, { action: "START" }).then(() => stop); } /** * Sets the presence for the logged in user. * @param {object} args The rich presence to pass. * @param {number} [pid] The application's process ID. Defaults to the executing process' PID. * @returns {Promise} */ setActivity(args = {}, pid = getPid()) { let timestamps; let assets; let party; let secrets; if (args.startTimestamp || args.endTimestamp) { timestamps = { start: args.startTimestamp, end: args.endTimestamp }; if (timestamps.start instanceof Date) { timestamps.start = Math.round(timestamps.start.getTime()); } if (timestamps.end instanceof Date) { timestamps.end = Math.round(timestamps.end.getTime()); } if (timestamps.start > 2147483647e3) { throw new RangeError("timestamps.start must fit into a unix timestamp"); } if (timestamps.end > 2147483647e3) { throw new RangeError("timestamps.end must fit into a unix timestamp"); } } if (args.largeImageKey || args.largeImageText || args.smallImageKey || args.smallImageText) { assets = { large_image: args.largeImageKey, large_text: args.largeImageText, small_image: args.smallImageKey, small_text: args.smallImageText }; } if (args.partySize || args.partyId || args.partyMax) { party = { id: args.partyId }; if (args.partySize || args.partyMax) { party.size = [args.partySize, args.partyMax]; } } if (args.matchSecret || args.joinSecret || args.spectateSecret) { secrets = { match: args.matchSecret, join: args.joinSecret, spectate: args.spectateSecret }; } return this.request(RPCCommands.SET_ACTIVITY, { pid, activity: { state: args.state, details: args.details, timestamps, assets, party, secrets, buttons: args.buttons, instance: !!args.instance } }); } /** * Clears the currently set presence, if any. This will hide the "Playing X" message * displayed below the user's name. * @param {number} [pid] The application's process ID. Defaults to the executing process' PID. * @returns {Promise} */ clearActivity(pid = getPid()) { return this.request(RPCCommands.SET_ACTIVITY, { pid }); } /** * Invite a user to join the game the RPC user is currently playing * @param {User} user The user to invite * @returns {Promise} */ sendJoinInvite(user) { return this.request(RPCCommands.SEND_ACTIVITY_JOIN_INVITE, { user_id: user.id || user }); } /** * Request to join the game the user is playing * @param {User} user The user whose game you want to request to join * @returns {Promise} */ sendJoinRequest(user) { return this.request(RPCCommands.SEND_ACTIVITY_JOIN_REQUEST, { user_id: user.id || user }); } /** * Reject a join request from a user * @param {User} user The user whose request you wish to reject * @returns {Promise} */ closeJoinRequest(user) { return this.request(RPCCommands.CLOSE_ACTIVITY_JOIN_REQUEST, { user_id: user.id || user }); } createLobby(type, capacity, metadata) { return this.request(RPCCommands.CREATE_LOBBY, { type, capacity, metadata }); } updateLobby(lobby, { type, owner, capacity, metadata } = {}) { return this.request(RPCCommands.UPDATE_LOBBY, { id: lobby.id || lobby, type, owner_id: owner && owner.id || owner, capacity, metadata }); } deleteLobby(lobby) { return this.request(RPCCommands.DELETE_LOBBY, { id: lobby.id || lobby }); } connectToLobby(id, secret) { return this.request(RPCCommands.CONNECT_TO_LOBBY, { id, secret }); } sendToLobby(lobby, data) { return this.request(RPCCommands.SEND_TO_LOBBY, { id: lobby.id || lobby, data }); } disconnectFromLobby(lobby) { return this.request(RPCCommands.DISCONNECT_FROM_LOBBY, { id: lobby.id || lobby }); } updateLobbyMember(lobby, user, metadata) { return this.request(RPCCommands.UPDATE_LOBBY_MEMBER, { lobby_id: lobby.id || lobby, user_id: user.id || user, metadata }); } getRelationships() { const types = Object.keys(RelationshipTypes); return this.request(RPCCommands.GET_RELATIONSHIPS).then((o) => o.relationships.map((r) => ({ ...r, type: types[r.type] }))); } /** * Subscribe to an event * @param {string} event Name of event e.g. `MESSAGE_CREATE` * @param {Object} [args] Args for event e.g. `{ channel_id: '1234' }` * @returns {Promise} */ async subscribe(event, args) { await this.request(RPCCommands.SUBSCRIBE, args, event); return { unsubscribe: () => this.request(RPCCommands.UNSUBSCRIBE, args, event) }; } /** * Destroy the client */ async destroy() { await this.transport.close(); } }; module2.exports = RPCClient; } }); // node_modules/discord-rpc/src/index.js var require_src = __commonJS({ "node_modules/discord-rpc/src/index.js"(exports, module2) { "use strict"; var util = require_util(); module2.exports = { Client: require_client(), register(id) { return util.register(`discord-${id}`); } }; } }); // src/main.ts var main_exports = {}; __export(main_exports, { default: () => ObsidianDiscordRPC }); module.exports = __toCommonJS(main_exports); var import_discord_rpc = __toESM(require_src()); var import_obsidian4 = require("obsidian"); // src/logger.ts var import_obsidian = require("obsidian"); var Logger = class { constructor(plugin) { this.plugin = plugin; } log(message, showPopups) { if (showPopups) { new import_obsidian.Notice(message); } console.log(`discordrpc: ${message}`); } logIgnoreNoNotice(message) { new import_obsidian.Notice(message); console.log(`discordrpc: ${message}`); } }; // src/settings/settings.ts var DiscordRPCSettings = class { constructor() { this.showVaultName = true; this.showCurrentFileName = true; this.showConnectionTimer = false; this.showPopups = true; this.customVaultName = ""; this.showFileExtension = false; this.useLoadedTime = false; this.connectOnStart = true; this.autoHideStatusBar = true; this.privacyMode = false; this.themeStyle = "default-new-dark" /* Default_new_dark */; } }; // src/settings/settings-tab.ts var import_obsidian2 = require("obsidian"); var DiscordRPCSettingsTab = class extends import_obsidian2.PluginSettingTab { constructor(app, plugin) { super(app, plugin); this.plugin = plugin; this.logger = new Logger(plugin); } display() { let { containerEl } = this; const plugin = this.plugin; containerEl.empty(); new import_obsidian2.Setting(containerEl).setName("Vault name").setHeading(); new import_obsidian2.Setting(containerEl).setName("Privacy mode").setDesc("Enable this to hide the name of the vault and Hide file names").addToggle( (boolean) => boolean.setValue(plugin.settings.privacyMode).onChange((value) => { plugin.settings.privacyMode = value; plugin.saveData(plugin.settings); plugin.setActivity("", "", ""); }) ); new import_obsidian2.Setting(containerEl).setName("Show vault name").setDesc( "Enable this to show the name of the vault you are working with." ).addToggle( (boolean) => boolean.setValue(plugin.settings.showVaultName).onChange((value) => { plugin.settings.showVaultName = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); }) ); new import_obsidian2.Setting(containerEl).setName("Set custom vault name").setDesc( "Change the vault name shown publicly. Leave blank to use your actual vault name." ).addText( (text) => text.setValue(plugin.settings.customVaultName).onChange((value) => { plugin.settings.customVaultName = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); }) ); new import_obsidian2.Setting(containerEl).setName("File name").setHeading(); new import_obsidian2.Setting(containerEl).setName("Show current file name").setDesc("Enable this to show the name of the file you are working on.").addToggle( (boolean) => boolean.setValue(plugin.settings.showCurrentFileName).onChange((value) => { plugin.settings.showCurrentFileName = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); }) ); new import_obsidian2.Setting(containerEl).setName("Show file extension").setDesc("Enable this to show file extension.").addToggle( (boolean) => boolean.setValue(plugin.settings.showFileExtension).onChange((value) => { plugin.settings.showFileExtension = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); }) ); new import_obsidian2.Setting(containerEl).setName("Time tracking").setHeading(); new import_obsidian2.Setting(containerEl).setName("Use obsidian total time").setDesc( "Enable to use the total time you have been using Obsidian, instead of the time spent editing a single file." ).addToggle((boolean) => { boolean.setValue(plugin.settings.useLoadedTime).onChange((value) => { plugin.settings.useLoadedTime = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); }); }); new import_obsidian2.Setting(containerEl).setName("Status bar").setHeading(); new import_obsidian2.Setting(containerEl).setName("Automatically hide status bar").setDesc( "Automatically hide status bar after successfully connecting to Discord." ).addToggle((boolean) => { boolean.setValue(plugin.settings.autoHideStatusBar).onChange((value) => { plugin.settings.autoHideStatusBar = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); }); }); new import_obsidian2.Setting(containerEl).setName("Show connected time").setDesc( "Show time spent editing file or time connected to Discord in the status bar." ).addToggle((boolean) => { boolean.setValue(plugin.settings.showConnectionTimer).onChange((value) => { plugin.settings.showConnectionTimer = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); plugin.statusBar.displayState(plugin.getState(), plugin.settings.autoHideStatusBar); }); }); new import_obsidian2.Setting(containerEl).setName("Startup behavior").setHeading(); new import_obsidian2.Setting(containerEl).setName("Automatically connect to Discord").setDesc( "Automatically connect to Discord on startup. You can always click the status bar to manually connect." ).addToggle((boolean) => { boolean.setValue(plugin.settings.connectOnStart).onChange((value) => { plugin.settings.connectOnStart = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); }); }); new import_obsidian2.Setting(containerEl).setName("Notices").setHeading(); new import_obsidian2.Setting(containerEl).setName("Show notices").setDesc("Enable this to show connection Notices.").addToggle( (boolean) => boolean.setValue(plugin.settings.showPopups).onChange((value) => { plugin.settings.showPopups = value; plugin.saveData(plugin.settings); plugin.setActivity( this.app.vault.getName(), plugin.currentFile.basename, plugin.currentFile.extension ); }) ); new import_obsidian2.Setting(containerEl).setName("Theme style").setHeading(); new import_obsidian2.Setting(containerEl).setName("Theme style").setDesc("Choose the theme style for Discord Rich Presence").addDropdown((dropdown) => dropdown.addOption("default-old-dark" /* Default_dark */, "Default Dark (Old)").addOption("default-old-light" /* Default_light */, "Default Light (Old)").addOption("default-new-dark" /* Default_new_dark */, "Default Dark (New)").addOption("default-new-light" /* Default_new_light */, "Default Light (New)").addOption("latte" /* Catppuccin_Latte */, "Catppuccin Latte").addOption("frappe" /* Catppuccin_Frappe */, "Catppuccin Frappe").addOption("macchiato" /* Catppuccin_Macchiato */, "Catppuccin Macchiato").addOption("mocha" /* Catppuccin_Mocha */, "Catppuccin Mocha").setValue(plugin.settings.themeStyle).onChange(async (value) => { var _a, _b, _c, _d; plugin.settings.themeStyle = value; await plugin.saveData(plugin.settings); if (plugin.getState() === 0 /* connected */) { await plugin.setActivity( plugin.app.vault.getName(), (_b = (_a = plugin.currentFile) == null ? void 0 : _a.basename) != null ? _b : "...", (_d = (_c = plugin.currentFile) == null ? void 0 : _c.extension) != null ? _d : "" ); } })); } }; // src/status-bar.ts var import_obsidian3 = require("obsidian"); var StatusBar = class _StatusBar { constructor(statusBarEl) { this.statusBarEl = statusBarEl; } displayState(state, autoHide) { switch (state) { case 0 /* connected */: this.displayConnected(autoHide ? 1e4 : 0); break; case 1 /* connecting */: this.statusBarEl.setText(`Connecting to Discord...`); break; case 2 /* disconnected */: this.statusBarEl.setText(`\u{1F5D8} Reconnect to Discord`); break; } } displayTimer(loadedTime) { this.statusBarEl.setText(`\u{1F30D} ${_StatusBar.millisecsToString((/* @__PURE__ */ new Date()).getTime() - loadedTime.getTime())}`); } displayConnected(timeout) { this.statusBarEl.setText(`\u{1F30D} Connected to Discord`); if (timeout && timeout > 0) { window.setTimeout(() => { this.statusBarEl.setText(""); }, timeout); } else { window.setTimeout(() => { this.statusBarEl.setText(`\u{1F30D}`); }, 5e3); } } /* Returns [HH:]mm:ss on the stopwatch https://github.com/grassbl8d/flexible-pomo-obsidian/blob/ae037e3710866863c5397f42af06c5540a807b10/src/timer.ts#L475 */ static millisecsToString(millisecs) { let formattedCountDown; if (millisecs >= 60 * 60 * 1e3) { formattedCountDown = import_obsidian3.moment.utc(millisecs).format("HH:mm:ss"); } else { formattedCountDown = import_obsidian3.moment.utc(millisecs).format("mm:ss"); } return formattedCountDown.toString(); } }; // src/main.ts var ObsidianDiscordRPC = class extends import_obsidian4.Plugin { constructor() { super(...arguments); this.logger = new Logger(); } setState(state) { this.state = state; } getState() { return this.state; } getApp() { return this.app; } getPluginManifest() { return this.manifest; } async onload() { let statusBarEl = this.addStatusBarItem(); this.statusBar = new StatusBar(statusBarEl); this.settings = await this.loadData() || new DiscordRPCSettings(); this.registerEvent( this.app.workspace.on("file-open", this.onFileOpen, this) ); this.registerInterval(window.setInterval(async () => { if (this.settings.showConnectionTimer && this.getState() == 0 /* connected */) { this.statusBar.displayTimer(this.settings.useLoadedTime ? this.loadedTime : this.lastSetTime); } }, 500)); this.registerDomEvent(statusBarEl, "click", async () => { if (this.getState() == 2 /* disconnected */) { await this.connectDiscord(); } else if (this.getState() == 0 /* connected */) { await this.disconnectDiscord(); } }); this.addSettingTab(new DiscordRPCSettingsTab(this.app, this)); this.addCommand({ id: "reconnect-discord", name: "Reconnect to Discord", callback: async () => await this.connectDiscord() }); this.addCommand({ id: "disconnect-discord", name: "Disconnect from Discord", callback: async () => await this.disconnectDiscord() }); if (this.settings.connectOnStart) { await this.connectDiscord(); const activeLeaf = this.app.workspace.activeLeaf; const files = this.app.vault.getMarkdownFiles(); if (activeLeaf) { const displayText = activeLeaf.getDisplayText(); files.forEach((file) => { if (file.basename === displayText) { this.onFileOpen(file); } }); } } else { this.setState(2 /* disconnected */); this.statusBar.displayState( this.getState(), this.settings.autoHideStatusBar ); } } async onFileOpen(file) { this.currentFile = file; if (this.getState() === 0 /* connected */) { await this.setActivity( this.app.vault.getName(), file.basename, file.extension ); } } async onunload() { await this.saveData(this.settings); this.rpc.clearActivity(); this.rpc.destroy(); } async connectDiscord() { this.loadedTime = /* @__PURE__ */ new Date(); this.lastSetTime = /* @__PURE__ */ new Date(); this.rpc = new import_discord_rpc.Client({ transport: "ipc" }); this.setState(1 /* connecting */); this.statusBar.displayState( this.getState(), this.settings.autoHideStatusBar ); this.rpc.once("ready", () => { this.setState(0 /* connected */); this.statusBar.displayState( this.getState(), this.settings.autoHideStatusBar ); this.logger.log("Connected to Discord", this.settings.showPopups); }); try { await this.rpc.login({ clientId: "1352970439684657152" }); await this.setActivity(this.app.vault.getName(), "...", ""); } catch (error) { this.setState(2 /* disconnected */); this.statusBar.displayState( this.getState(), this.settings.autoHideStatusBar ); this.logger.log("Failed to connect to Discord", this.settings.showPopups); } } async disconnectDiscord() { this.rpc.clearActivity(); this.rpc.destroy(); this.setState(2 /* disconnected */); this.statusBar.displayState( this.getState(), this.settings.autoHideStatusBar ); this.logger.log("Disconnected from Discord", this.settings.showPopups); } async setActivity(vaultName, fileName, fileExtension) { if (this.getState() === 0 /* connected */) { let vault; if (this.settings.customVaultName === "") { vault = vaultName; } else { vault = this.settings.customVaultName; } let file; if (this.settings.showFileExtension) { file = fileName + "." + fileExtension; } else { file = fileName; } let date; if (this.settings.useLoadedTime) { date = this.loadedTime; } else { date = /* @__PURE__ */ new Date(); } this.lastSetTime = date; if (this.settings.privacyMode) { await this.rpc.setActivity({ details: `Editing Notes`, state: `Working in a Vault`, startTimestamp: date, largeImageKey: this.settings.themeStyle, largeImageText: "Obsidian" }); } else if (this.settings.showVaultName && this.settings.showCurrentFileName) { await this.rpc.setActivity({ details: `Editing ${file}`, state: `Vault: ${vault}`, startTimestamp: date, largeImageKey: this.settings.themeStyle, largeImageText: "Obsidian" }); } else if (this.settings.showVaultName) { await this.rpc.setActivity({ state: `Vault: ${vault}`, startTimestamp: date, largeImageKey: this.settings.themeStyle, largeImageText: "Obsidian" }); } else if (this.settings.showCurrentFileName) { await this.rpc.setActivity({ details: `Editing ${file}`, startTimestamp: date, largeImageKey: this.settings.themeStyle, largeImageText: "Obsidian" }); } else { await this.rpc.setActivity({ startTimestamp: date, largeImageKey: this.settings.themeStyle, largeImageText: "Obsidian" }); } } } }; /* nosourcemap */