1567 lines
51 KiB
JavaScript
1567 lines
51 KiB
JavaScript
/*
|
|
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<RPCClient>}
|
|
*/
|
|
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<Guild>}
|
|
*/
|
|
getGuild(id, timeout) {
|
|
return this.request(RPCCommands.GET_GUILD, { guild_id: id, timeout });
|
|
}
|
|
/**
|
|
* Fetch all guilds
|
|
* @param {number} [timeout] Timeout request
|
|
* @returns {Promise<Collection<Snowflake, Guild>>}
|
|
*/
|
|
getGuilds(timeout) {
|
|
return this.request(RPCCommands.GET_GUILDS, { timeout });
|
|
}
|
|
/**
|
|
* Get a channel
|
|
* @param {Snowflake} id Channel ID
|
|
* @param {number} [timeout] Timeout request
|
|
* @returns {Promise<Channel>}
|
|
*/
|
|
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<Collection<Snowflake, Channel>>}
|
|
*/
|
|
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<Function>}
|
|
*/
|
|
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<Object>}
|
|
*/
|
|
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 */ |