smule.js 1.3.2 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1301,18 +1301,17 @@ var SmuleUrls;
1301
1301
  import "@xmpp/xml";
1302
1302
  import EventEmitter from "events";
1303
1303
  import "@xmpp/jid";
1304
+ import { randomUUID as randomUUID2 } from "crypto";
1304
1305
  var SmuleLiveChat = class {
1305
1306
  events = new EventEmitter();
1306
1307
  state = "closed";
1307
1308
  client;
1308
1309
  jid;
1309
- ongoingIq = false;
1310
- iqHasMore = false;
1311
- lastIqId = "0";
1310
+ iqs = {};
1312
1311
  roomJID = null;
1313
1312
  roomUsers = [];
1314
1313
  chat = { messages: [] };
1315
- constructor(userId, session, host = SmuleUrls.userChat, roomJID) {
1314
+ constructor(userId, session, host = SmuleUrls.cfireChat, roomJID) {
1316
1315
  this.client = client({
1317
1316
  service: "xmpp://" + host,
1318
1317
  domain: host,
@@ -1360,6 +1359,9 @@ var SmuleLiveChat = class {
1360
1359
  )
1361
1360
  )
1362
1361
  );
1362
+ this.sendIqQuery("http://jabber.org/protocol/disco#info", (el) => {
1363
+ console.log("reply from disco", el);
1364
+ });
1363
1365
  }
1364
1366
  /**
1365
1367
  * Disconnects the client from the XMPP server.
@@ -1371,83 +1373,41 @@ var SmuleLiveChat = class {
1371
1373
  */
1372
1374
  async disconnect() {
1373
1375
  try {
1376
+ await this.client.send(xml("presence", { type: "unavailable" }));
1374
1377
  await this.client.stop();
1375
1378
  } catch {
1376
1379
  }
1377
1380
  }
1378
- /**
1379
- * Send a chat state to the server. This is used to
1380
- * signal whether you are currently active or not.
1381
- *
1382
- * active -> You're active
1383
- *
1384
- * composing -> Typing
1385
- *
1386
- * paused -> Just stopped typing
1387
- *
1388
- * inactive -> You're inactive
1389
- *
1390
- * gone -> You're hidden / disconnected / You've left the chat
1391
- *
1392
- * @param state One of `active`, `composing`, `paused`, `inactive`, or `gone`.
1393
- * Default is `active`
1394
- */
1395
- async sendChatState(to, state = "active") {
1396
- if (typeof to != "string" && "accountId" in to) to = this.getJIDFromUserId(to.accountId);
1397
- await this.client.send(
1381
+ sendIq(data, callback, iqType = "get") {
1382
+ const id = randomUUID2();
1383
+ this.iqs[id] = callback;
1384
+ this.client.send(
1398
1385
  xml(
1399
- "message",
1400
- { to: to.toString(), type: "chat" },
1401
- xml(
1402
- "chatstate",
1403
- { xmlns: "http://jabber.org/protocol/chatstates" },
1404
- state
1405
- )
1386
+ "iq",
1387
+ { from: this.jid.toString(), to: this.roomJID, type: iqType, id },
1388
+ data
1406
1389
  )
1407
1390
  );
1408
1391
  }
1409
- /**
1410
- * Loads the entire message history
1411
- * @param limit The maximum number of messages to fetch. Default is 50.
1412
- * @remarks This currently recurses until it loads ALL archived messages.
1413
- * This means that it will take a long time to load all messages.
1414
- * @remarks Filtering by a specific JID may not work yet
1415
- */
1416
- async loadMessageHistory(limit = 50, before = null, after = null, jid) {
1417
- this._log("Loading live chat history...");
1418
- this.ongoingIq = true;
1419
- await this.client.send(
1420
- xml(
1421
- "iq",
1422
- { from: this.jid.toString(), to: this.roomJID, type: "get", id: "meow" },
1423
- xml(
1424
- "query",
1425
- { xmlns: "http://jabber.org/protocol/muc#history" }
1426
- )
1427
- )
1392
+ sendIqQuery(xmlns, callback, iqType = "get") {
1393
+ this.sendIq(
1394
+ xml("query", { xmlns }),
1395
+ callback,
1396
+ iqType
1428
1397
  );
1429
- while (this.ongoingIq) await new Promise((resolve) => setTimeout(resolve, 100));
1430
1398
  }
1431
1399
  /**
1432
- * Send a text message
1433
- * @param jid The JID to send the message to
1400
+ * Send a text message to the livestream
1434
1401
  * @param message The message body
1435
1402
  */
1436
- async sendTextMessage(jid, message) {
1437
- if (typeof jid != "string" && "accountId" in jid) jid = this.getJIDFromUserId(jid.accountId);
1403
+ async sendTextMessage(message) {
1438
1404
  await this.client.send(
1439
1405
  xml(
1440
1406
  "message",
1441
- { to: jid.toString(), type: "groupchat" },
1407
+ { to: this.roomJID, type: "groupchat" },
1442
1408
  xml("body", {}, message)
1443
1409
  )
1444
1410
  );
1445
- const data = {
1446
- sender: parseInt(this.jid.getLocal()),
1447
- content: message
1448
- };
1449
- this.chat[this.getUserIdFromJID(jid.toString())].messages.push(data);
1450
- this.events.emit("message", data);
1451
1411
  }
1452
1412
  /**
1453
1413
  * Read-only jid to prevent any bugs
@@ -1560,6 +1520,23 @@ var SmuleLiveChat = class {
1560
1520
  this._log("Got host left!", data2);
1561
1521
  this.events.emit("host-left", data2);
1562
1522
  }
1523
+ child = el.getChild("song-listen");
1524
+ if (child) {
1525
+ const data2 = {
1526
+ arrKey: child.getChild("arrangement-key").getText(),
1527
+ hostSessionId: child.getChild("host-session-id").getText()
1528
+ };
1529
+ this._log("Got song listen!", data2);
1530
+ this.events.emit("song-listen", data2);
1531
+ }
1532
+ child = el.getChild("campfire-ended");
1533
+ if (child) {
1534
+ const data2 = {
1535
+ reason: child.getChild("reason").getText()
1536
+ };
1537
+ this._log("Got stop livestream!", data2);
1538
+ this.events.emit("stop-livestream", data2);
1539
+ }
1563
1540
  child = el.getChild("result");
1564
1541
  if (!child) return;
1565
1542
  child = child.getChild("forwarded");
@@ -1583,15 +1560,17 @@ var SmuleLiveChat = class {
1583
1560
  if (child) {
1584
1561
  child = child.getChild("item");
1585
1562
  if (child) {
1586
- if (!el.getAttr("jid")) return;
1587
- const data = {
1588
- user: this.getUserIdFromJID(el.getAttr("jid")),
1589
- role: child.getAttr("role"),
1590
- affiliation: child.getAttr("affiliation")
1591
- };
1592
- this._log("Got presence!", data);
1593
- this.roomUsers.push(data);
1594
- this.events.emit("presence", data);
1563
+ if (!el.getAttr("jid")) {
1564
+ } else {
1565
+ const data = {
1566
+ user: this.getUserIdFromJID(el.getAttr("jid")),
1567
+ role: child.getAttr("role"),
1568
+ affiliation: child.getAttr("affiliation")
1569
+ };
1570
+ this._log("Got presence!", data);
1571
+ this.roomUsers.push(data);
1572
+ this.events.emit("presence", data);
1573
+ }
1595
1574
  }
1596
1575
  }
1597
1576
  }
@@ -1688,22 +1667,11 @@ var SmuleLiveChat = class {
1688
1667
  this.parsePresence(el);
1689
1668
  } else {
1690
1669
  if (el.is("iq")) {
1691
- let child = el.getChild("fin");
1692
- if (child) {
1693
- if (child.getAttr("complete") == "false") {
1694
- this.iqHasMore = true;
1695
- child = child.getChild("set");
1696
- if (child) {
1697
- child = child.getChild("last");
1698
- if (child) {
1699
- this.lastIqId = child.getText();
1700
- }
1701
- }
1702
- } else {
1703
- this.iqHasMore = false;
1704
- }
1670
+ const id = el.getAttr("id");
1671
+ if (id) {
1672
+ this.iqs[id](el);
1673
+ delete this.iqs[id];
1705
1674
  }
1706
- this.ongoingIq = false;
1707
1675
  }
1708
1676
  this._log("Stanza!", el.toString());
1709
1677
  }
@@ -2140,17 +2108,14 @@ import { client as client2, xml as xml2 } from "@xmpp/client";
2140
2108
  import "@xmpp/xml";
2141
2109
  import EventEmitter2 from "events";
2142
2110
  import "@xmpp/jid";
2111
+ import { randomUUID as randomUUID3 } from "crypto";
2143
2112
  var SmuleChat = class {
2144
2113
  events = new EventEmitter2();
2145
2114
  state = "closed";
2146
2115
  client;
2147
2116
  jid;
2148
- ongoingIq = false;
2149
- iqHasMore = false;
2150
- lastIqId = "0";
2151
- isLive = false;
2117
+ iqs = {};
2152
2118
  roomJID = null;
2153
- roomUsers = [];
2154
2119
  chats = {};
2155
2120
  constructor(userId, session, host = SmuleUrls.userChat, roomJID) {
2156
2121
  this.client = client2({
@@ -2161,7 +2126,6 @@ var SmuleChat = class {
2161
2126
  username: userId + "",
2162
2127
  password: session
2163
2128
  });
2164
- this.isLive = host != SmuleUrls.userChat || !!roomJID;
2165
2129
  this.roomJID = roomJID;
2166
2130
  this.client.on("close", (el) => this.onClose(el));
2167
2131
  this.client.on("closing", () => this.onClosing());
@@ -2184,27 +2148,7 @@ var SmuleChat = class {
2184
2148
  async connect() {
2185
2149
  this.jid = await this.client.start();
2186
2150
  this._log("Connected as:", this.jid.getLocal() + "@" + this.jid.getDomain());
2187
- if (!this.isLive && !this.roomJID) {
2188
- this.client.send(xml2("presence", {}));
2189
- } else {
2190
- this.client.send(
2191
- xml2(
2192
- "presence",
2193
- { to: this.roomJID + "/" + this.jid.getLocal() },
2194
- xml2(
2195
- "x",
2196
- { xmlns: "http://jabber.org/protocol/muc" },
2197
- xml2(
2198
- "password"
2199
- ),
2200
- xml2(
2201
- "history",
2202
- { maxstanzas: "1" }
2203
- )
2204
- )
2205
- )
2206
- );
2207
- }
2151
+ this.client.send(xml2("presence", {}));
2208
2152
  }
2209
2153
  /**
2210
2154
  * Disconnects the client from the XMPP server.
@@ -2216,10 +2160,29 @@ var SmuleChat = class {
2216
2160
  */
2217
2161
  async disconnect() {
2218
2162
  try {
2163
+ await this.client.send(xml2("presence", { type: "unavailable" }));
2219
2164
  await this.client.stop();
2220
2165
  } catch {
2221
2166
  }
2222
2167
  }
2168
+ sendIq(data, callback, iqType = "get") {
2169
+ const id = randomUUID3();
2170
+ this.iqs[id] = callback;
2171
+ this.client.send(
2172
+ xml2(
2173
+ "iq",
2174
+ { from: this.jid.toString(), to: this.roomJID, type: iqType, id },
2175
+ data
2176
+ )
2177
+ );
2178
+ }
2179
+ sendIqQuery(xmlns, callback, iqType = "get") {
2180
+ this.sendIq(
2181
+ xml2("query", { xmlns }),
2182
+ callback,
2183
+ iqType
2184
+ );
2185
+ }
2223
2186
  /**
2224
2187
  * Send a chat state to the server. This is used to
2225
2188
  * signal whether you are currently active or not.
@@ -2259,50 +2222,29 @@ var SmuleChat = class {
2259
2222
  * @remarks Filtering by a specific JID may not work yet
2260
2223
  */
2261
2224
  async loadMessageHistory(limit = 50, before = null, after = null, jid) {
2262
- if (!this.isLive) {
2263
- if (this.ongoingIq) this._log("Waiting for previous iq to finish...");
2264
- while (this.ongoingIq) await new Promise((resolve) => setTimeout(resolve, 100));
2265
- if (jid)
2266
- this._log(`Loading ${limit} messages with ${jid}...`);
2267
- else
2268
- this._log(`Loading ${limit} messages from history...`);
2269
- if (!before && !after && !jid) this.chats = {};
2270
- this.ongoingIq = true;
2271
- await this.client.send(
2272
- xml2(
2273
- "iq",
2274
- { type: "set", id: "mam-query" },
2275
- xml2(
2276
- "query",
2277
- { xmlns: "urn:xmpp:mam:2" },
2278
- xml2(
2279
- "set",
2280
- { xmlns: "http://jabber.org/protocol/rsm" },
2281
- xml2("max", {}, limit.toString()),
2282
- before ? xml2("before", {}, before.toString()) : null,
2283
- after ? xml2("after", {}, after.toString()) : null
2284
- ),
2285
- jid ? xml2("with", {}, jid.toString()) : null
2286
- )
2287
- )
2288
- );
2289
- while (this.ongoingIq) await new Promise((resolve) => setTimeout(resolve, 100));
2290
- if (this.iqHasMore) await this.loadMessageHistory(limit, null, this.lastIqId, jid);
2291
- } else {
2292
- this._log("Loading live chat history...");
2293
- this.ongoingIq = true;
2294
- await this.client.send(
2225
+ if (jid)
2226
+ this._log(`Loading ${limit} messages with ${jid}...`);
2227
+ else
2228
+ this._log(`Loading ${limit} messages from history...`);
2229
+ if (!before && !after && !jid) this.chats = {};
2230
+ this.sendIq(
2231
+ xml2(
2232
+ "query",
2233
+ { xmlns: "urn:xmpp:mam:2" },
2295
2234
  xml2(
2296
- "iq",
2297
- { from: this.jid.toString(), to: this.roomJID, type: "get", id: "meow" },
2298
- xml2(
2299
- "query",
2300
- { xmlns: "http://jabber.org/protocol/muc#history" }
2301
- )
2302
- )
2303
- );
2304
- while (this.ongoingIq) await new Promise((resolve) => setTimeout(resolve, 100));
2305
- }
2235
+ "set",
2236
+ { xmlns: "http://jabber.org/protocol/rsm" },
2237
+ xml2("max", {}, limit.toString()),
2238
+ before ? xml2("before", {}, before.toString()) : null,
2239
+ after ? xml2("after", {}, after.toString()) : null
2240
+ ),
2241
+ jid ? xml2("with", {}, jid.toString()) : null
2242
+ ),
2243
+ (el) => {
2244
+ this._log("Finished loading history!", el.toString());
2245
+ },
2246
+ "set"
2247
+ );
2306
2248
  }
2307
2249
  /**
2308
2250
  * Send a text message
@@ -2314,16 +2256,10 @@ var SmuleChat = class {
2314
2256
  await this.client.send(
2315
2257
  xml2(
2316
2258
  "message",
2317
- { to: jid.toString(), type: this.isLive ? "groupchat" : "chat" },
2259
+ { to: jid.toString(), type: "chat" },
2318
2260
  xml2("body", {}, message)
2319
2261
  )
2320
2262
  );
2321
- let data = {
2322
- sender: parseInt(this.jid.getLocal()),
2323
- content: message
2324
- };
2325
- this.chats[this.getUserIdFromJID(jid.toString())].messages.push(data);
2326
- this.events.emit("message", data);
2327
2263
  }
2328
2264
  /**
2329
2265
  * Send a performance / recording
@@ -2363,25 +2299,6 @@ var SmuleChat = class {
2363
2299
  )
2364
2300
  );
2365
2301
  }
2366
- //TODO - Most definitely not required
2367
- async archiveMessage(jid, message) {
2368
- if (typeof jid != "string" && "accountId" in jid) jid = this.getJIDFromUserId(jid.accountId);
2369
- await this.client.send(
2370
- xml2(
2371
- "iq",
2372
- { type: "set" },
2373
- xml2(
2374
- "archive",
2375
- { xmlns: "urn:xmpp:mam:2" },
2376
- xml2(
2377
- "item",
2378
- { with: jid, id: Math.random().toString(16).substring(2, 8) },
2379
- xml2("body", {}, message)
2380
- )
2381
- )
2382
- )
2383
- );
2384
- }
2385
2302
  /**
2386
2303
  * Read-only jid to prevent any bugs
2387
2304
  * @returns user's JID
@@ -2405,7 +2322,6 @@ var SmuleChat = class {
2405
2322
  */
2406
2323
  getJIDFromUserId(userId) {
2407
2324
  if (typeof userId != "string" && typeof userId != "number" && "accountId" in userId) userId = userId.accountId;
2408
- if (this.isLive) return this.roomJID + "/" + userId;
2409
2325
  return userId + "@" + this.jid.getDomain();
2410
2326
  }
2411
2327
  //* Processes all message-like elements
@@ -2430,7 +2346,6 @@ var SmuleChat = class {
2430
2346
  }
2431
2347
  child = el.getChild("body");
2432
2348
  const perfChild = el.getChild("performance");
2433
- const perfStartChild = el.getChild("performance-start");
2434
2349
  if (child && (child.getText().trim().length > 0 || perfChild)) {
2435
2350
  this._log("Got message!", child.getText());
2436
2351
  let performanceKey2 = void 0;
@@ -2461,7 +2376,8 @@ var SmuleChat = class {
2461
2376
  content: child.getText(),
2462
2377
  sender: this.getUserIdFromJID(child.parent.getAttr("from")),
2463
2378
  id: child.parent.getAttr("id"),
2464
- performanceKey
2379
+ performanceKey,
2380
+ systemMessage: !!child.parent.getChild("smule-system-msg")
2465
2381
  };
2466
2382
  let chat = this.jid.getLocal().includes(data.sender + "") ? this.getUserIdFromJID(child.parent.getAttr("to")) : data.sender;
2467
2383
  this.events.emit("history", data);
@@ -2470,25 +2386,6 @@ var SmuleChat = class {
2470
2386
  }
2471
2387
  parsePresence(el) {
2472
2388
  if (el.children.length < 1) return;
2473
- if (this.isLive) {
2474
- let child = el.getChildByAttr("xmlns", "http://jabber.org/protocol/muc#user");
2475
- if (child) {
2476
- child = child.getChild("item");
2477
- if (child) {
2478
- if (!el.getAttr("jid")) return;
2479
- let user = this.getUserIdFromJID(el.getAttr("jid"));
2480
- let role = child.getAttr("role");
2481
- let affiliation = child.getAttr("affiliation");
2482
- let data = {
2483
- user,
2484
- role,
2485
- affiliation
2486
- };
2487
- this.roomUsers.push(data);
2488
- this.events.emit("presence", data);
2489
- }
2490
- }
2491
- }
2492
2389
  }
2493
2390
  /**
2494
2391
  * Fetches the chats currently loaded
@@ -2506,9 +2403,6 @@ var SmuleChat = class {
2506
2403
  if (!(user in this.chats)) this.chats[user] = { messages: [] };
2507
2404
  return this.chats[user];
2508
2405
  }
2509
- fetchUsers() {
2510
- return this.roomUsers;
2511
- }
2512
2406
  //#region Internal events
2513
2407
  onClose(el) {
2514
2408
  this._log("Closed!:", el);
@@ -2592,22 +2486,11 @@ var SmuleChat = class {
2592
2486
  this.parsePresence(el);
2593
2487
  } else {
2594
2488
  if (el.is("iq")) {
2595
- let child = el.getChild("fin");
2596
- if (child) {
2597
- if (child.getAttr("complete") == "false") {
2598
- this.iqHasMore = true;
2599
- child = child.getChild("set");
2600
- if (child) {
2601
- child = child.getChild("last");
2602
- if (child) {
2603
- this.lastIqId = child.getText();
2604
- }
2605
- }
2606
- } else {
2607
- this.iqHasMore = false;
2608
- }
2489
+ const id = el.getAttr("id");
2490
+ if (id) {
2491
+ this.iqs[id](el);
2492
+ delete this.iqs[id];
2609
2493
  }
2610
- this.ongoingIq = false;
2611
2494
  }
2612
2495
  this._log("Stanza!", el.toString());
2613
2496
  }
@@ -2615,13 +2498,13 @@ var SmuleChat = class {
2615
2498
  //#endregion Internal events
2616
2499
  //#region Logging
2617
2500
  _log(...args) {
2618
- console.log(this.isLive ? "[SmuleLiveChat]" : "[SmuleChat]", ...args);
2501
+ console.log("[SmuleChat]", ...args);
2619
2502
  }
2620
2503
  _warn(...args) {
2621
- console.warn(this.isLive ? "[SmuleLiveChat]" : "[SmuleChat]", ...args);
2504
+ console.warn("[SmuleChat]", ...args);
2622
2505
  }
2623
2506
  _error(...args) {
2624
- console.error(this.isLive ? "[SmuleLiveChat]" : "[SmuleChat]", ...args);
2507
+ console.error("[SmuleChat]", ...args);
2625
2508
  }
2626
2509
  //#endregion Logging
2627
2510
  };
@@ -2630,7 +2513,7 @@ var SmuleChat = class {
2630
2513
  import { readFileSync } from "fs";
2631
2514
  import * as crypto from "crypto";
2632
2515
  import "@xmpp/jid";
2633
- var APP_VERSION = "12.0.9";
2516
+ var APP_VERSION = "12.6.9";
2634
2517
  var SmuleDigest;
2635
2518
  ((SmuleDigest2) => {
2636
2519
  const SALT = `c2250918de500e32c37842f2d25d4d8210992a0ae96a7f36c4c9703cc675d02b92968bc4fa7feada`;
@@ -3174,13 +3057,37 @@ var Smule = class {
3174
3057
  * Creates a new spark chat
3175
3058
  * @param address The JID address of the chat partner
3176
3059
  * @param type Whether the JID address is an individual or a group
3177
- * @returns idk
3178
3060
  */
3179
3061
  create: async (address, type = "ACCT") => {
3180
3062
  const req = await this.internal._createRequest(SmuleUrls.SparkChatUpdate, { add: [{ name: address, type }], remove: [] });
3063
+ this.internal._handleNon200(req);
3064
+ },
3065
+ /**
3066
+ * Deletes an existing spark chat
3067
+ * @param address The JID address of the chat partner
3068
+ * @param type Whether the JID address is an individual or a group
3069
+ */
3070
+ delete: async (address, type = "ACCT") => {
3071
+ const req = await this.internal._createRequest(SmuleUrls.SparkChatUpdate, { remove: [{ name: address, type }], add: [] });
3072
+ this.internal._handleNon200(req);
3073
+ },
3074
+ /**
3075
+ * Fetches your existing chats
3076
+ * @param type Whether an individual or a group
3077
+ * @returns Your inbox and your message requests
3078
+ */
3079
+ fetchInboxes: async (type = "ACCT") => {
3080
+ const req = await this.internal._createRequest(SmuleUrls.SparkChatList, { type, limit: 200 });
3181
3081
  if (!this.internal._handleNon200(req)) return;
3182
3082
  return this.internal._getResponseData(req);
3183
3083
  },
3084
+ /**
3085
+ * Marks you as offline to your chats
3086
+ */
3087
+ markOffline: async () => {
3088
+ const req = await this.internal._createRequest(SmuleUrls.SparkChatOffline, {});
3089
+ this.internal._handleNon200(req);
3090
+ },
3184
3091
  /**
3185
3092
  * Creates a connection to the XMPP chat server
3186
3093
  */
@@ -4351,9 +4258,9 @@ var Smule = class {
4351
4258
  * @param to The user to send the message to
4352
4259
  * @param message The message body
4353
4260
  */
4354
- sendTextMessage: async (to, message) => {
4261
+ sendTextMessage: async (message) => {
4355
4262
  if (!this.liveChatSession) return;
4356
- await this.liveChatSession.sendTextMessage(to, message);
4263
+ await this.liveChatSession.sendTextMessage(message);
4357
4264
  },
4358
4265
  /**
4359
4266
  * Fetch all loaded chats
@@ -4366,27 +4273,47 @@ var Smule = class {
4366
4273
  fetchUsers: () => {
4367
4274
  if (!this.liveChatSession) return;
4368
4275
  return this.liveChatSession.fetchUsers();
4369
- },
4370
- /**
4371
- * Loads the entire message history
4372
- * @param limit How many messages
4373
- * @param before Messages before this
4374
- * @param after Messages after this
4375
- * @param user The chat partner
4376
- *
4377
- * @remarks This currently recurses until it loads ALL archived messages.
4378
- * This means that it will take a long time to load all messages.
4379
- * @remarks Filtering by a specific user may not work yet
4380
- */
4381
- loadMessageHistory: async (limit = 50, before = null, after = null, user) => {
4382
- if (!this.liveChatSession) return;
4383
- await this.liveChatSession.loadMessageHistory(limit, before, after, user);
4384
4276
  }
4385
4277
  },
4278
+ /**
4279
+ * Fetches ("syncs") a livestream (campfire) so you can connect to it
4280
+ *
4281
+ * @param campfireId The campfire's id
4282
+ * @returns Data regarding the campfire and the streaming details
4283
+ */
4386
4284
  fetch: async (campfireId) => {
4387
4285
  const req = await this.internal._createRequest(SmuleUrls.CfireSync, { campfireId });
4388
4286
  if (!this.internal._handleNon200(req)) return;
4389
4287
  return this.internal._getResponseData(req);
4288
+ },
4289
+ /**
4290
+ * Fetches gifts that have been sent to a live
4291
+ *
4292
+ * @param campfireId The campfire's id
4293
+ * @param cursor The starting point
4294
+ * @param limit How many results
4295
+ * @returns A list of gifts data
4296
+ */
4297
+ fetchRecentGifts: async (campfireId, cursor = "start", limit = 10) => {
4298
+ const req = await this.internal._createRequest(SmuleUrls.GiftRecentTransactions, { campfireId, cursor, limit, animationVersion: "V2", extraGiftTypes: ["SYSTEM"], previewVersion: "PNG", type: "CFIRE" });
4299
+ if (!this.internal._handleNon200(req)) return;
4300
+ return this.internal._getResponseData(req);
4301
+ },
4302
+ /**
4303
+ * Sign up as available to sing
4304
+ * @param campfireId The livestream's id
4305
+ */
4306
+ joinToSing: async (campfireId) => {
4307
+ const req = await this.internal._createRequest(SmuleUrls.CfireSignupAdd, { campfireId, message: "I'm available to sing" });
4308
+ this.internal._handleNon200(req);
4309
+ },
4310
+ /**
4311
+ * Revoke your availability to sing
4312
+ * @param campfireId The livestream's id
4313
+ */
4314
+ revokeJoinToSing: async (campfireId) => {
4315
+ const req = await this.internal._createRequest(SmuleUrls.CfireSignupRemove, { campfireId });
4316
+ this.internal._handleNon200(req);
4390
4317
  }
4391
4318
  };
4392
4319
  groups = {