· 6 years ago · Mar 29, 2020, 01:12 PM
1//META{"name":"AutoStartRichPresence","website":"https://github.com/Mega-Mewthree/BetterDiscordPlugins/tree/master/Plugins/AutoStartRichPresence","source":"https://github.com/Mega-Mewthree/BetterDiscordPlugins/blob/master/Plugins/AutoStartRichPresence/AutoStartRichPresence.plugin.js"}*//
2
3/*
4-----BEGIN PGP SIGNED MESSAGE-----
5Hash: SHA512
6
7*/
8/*
9MIT License
10
11Copyright (c) 2018-2019 Mega_Mewthree
12
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in all
21copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29SOFTWARE.
30*/
31
32// Updated April 14th, 2019.
33
34let RPClient;
35
36(() => {
37 const path = require("path");
38 const fs = require("fs");
39 const EventEmitter = require("events");
40
41 // snekfetch library
42 let snekfetch;
43 (() => {
44 /*
45 MIT License
46
47 Copyright (c) 2017 Gus Caplan
48
49 Permission is hereby granted, free of charge, to any person obtaining a copy
50 of this software and associated documentation files (the "Software"), to deal
51 in the Software without restriction, including without limitation the rights
52 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
53 copies of the Software, and to permit persons to whom the Software is
54 furnished to do so, subject to the following conditions:
55
56 The above copyright notice and this permission notice shall be included in all
57 copies or substantial portions of the Software.
58
59 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
63 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
64 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
65 SOFTWARE.
66 */
67 let transport;
68 (() => {
69 const zlib = require('zlib');
70 const {
71 parse: UrlParse,
72 resolve: UrlResolve
73 } = require('url');
74 let socket;
75 (() => {
76 const tls = require('tls');
77 const http = require('http');
78 const https = require('https');
79 // lazy require http2 because it emits a warning
80 let http2;
81
82 const hasHttp2 = (() => {
83 const [a, b, c] = process.version.split('.');
84 return (+a.slice(1) * 0x1000) + (+b * 0x100) + +c >= 38912;
85 })();
86 const ALPNProtocols = hasHttp2 ? ['h2', 'http/1.1'] : ['http/1.1'];
87
88 function connectHttp(opt) {
89 const req = http.request(opt);
90 return Promise.resolve({
91 req
92 });
93 }
94
95 function http2req(connection, opt) {
96 return connection.request(Object.assign({
97 ':path': opt.path,
98 ':method': opt.method,
99 ':authority': opt.host,
100 }, opt.headers));
101 }
102
103 function connectHttps(opt) {
104 return new Promise((resolve, reject) => {
105 const port = opt.port = +opt.port || 443;
106 const socket = tls.connect({
107 host: opt.host,
108 port,
109 servername: opt.host,
110 ALPNProtocols,
111 });
112 socket.once('error', reject);
113 socket.once('secureConnect', () => {
114 switch (socket.alpnProtocol) {
115 case false:
116 case 'http/1.1':
117 {
118 const req = https.request(Object.assign({
119 createConnection: () => socket,
120 }, opt));
121 resolve({
122 req
123 });
124 break;
125 }
126 case 'h2':
127 {
128 if (http2 === undefined) {
129 http2 = require('http2');
130 }
131
132 const connection = http2.connect({
133 host: opt.host,
134 port,
135 }, {
136 createConnection: () => socket,
137 });
138
139 connection.port = opt.port;
140 connection.host = opt.host;
141
142 const req = http2req(connection, opt);
143 resolve({
144 req,
145 http2: true,
146 connection
147 });
148 break;
149 }
150 default:
151 reject(new Error(`No supported ALPN protocol was negotiated, got ${socket.alpnProtocol}`));
152 break;
153 }
154 });
155 });
156 }
157
158 socket = (options) =>
159 (options.protocol === 'https:' ? connectHttps : connectHttp)(options);
160
161 socket.http2req = http2req;
162 })();
163 const Stream = require('stream');
164 const querystring = require('querystring');
165 const {
166 METHODS,
167 STATUS_CODES
168 } = require('http');
169 let FormData;
170 (() => {
171 const path = require('path');
172 let mime;
173 (() => {
174 const mimes = {
175 "123": "application/vnd.lotus-1-2-3",
176 "ez": "application/andrew-inset",
177 "aw": "application/applixware",
178 "atom": "application/atom+xml",
179 "atomcat": "application/atomcat+xml",
180 "atomsvc": "application/atomsvc+xml",
181 "bdoc": "application/x-bdoc",
182 "ccxml": "application/ccxml+xml",
183 "cdmia": "application/cdmi-capability",
184 "cdmic": "application/cdmi-container",
185 "cdmid": "application/cdmi-domain",
186 "cdmio": "application/cdmi-object",
187 "cdmiq": "application/cdmi-queue",
188 "cu": "application/cu-seeme",
189 "mpd": "application/dash+xml",
190 "davmount": "application/davmount+xml",
191 "dbk": "application/docbook+xml",
192 "dssc": "application/dssc+der",
193 "xdssc": "application/dssc+xml",
194 "ecma": "application/ecmascript",
195 "emma": "application/emma+xml",
196 "epub": "application/epub+zip",
197 "exi": "application/exi",
198 "pfr": "application/font-tdpfr",
199 "woff": "application/font-woff",
200 "woff2": "application/font-woff2",
201 "geojson": "application/geo+json",
202 "gml": "application/gml+xml",
203 "gpx": "application/gpx+xml",
204 "gxf": "application/gxf",
205 "stk": "application/hyperstudio",
206 "ink": "application/inkml+xml",
207 "inkml": "application/inkml+xml",
208 "ipfix": "application/ipfix",
209 "jar": "application/java-archive",
210 "war": "application/java-archive",
211 "ear": "application/java-archive",
212 "ser": "application/java-serialized-object",
213 "class": "application/java-vm",
214 "js": "application/javascript",
215 "json": "application/json",
216 "map": "application/json",
217 "json5": "application/json5",
218 "jsonml": "application/jsonml+json",
219 "jsonld": "application/ld+json",
220 "lostxml": "application/lost+xml",
221 "hqx": "application/mac-binhex40",
222 "cpt": "application/mac-compactpro",
223 "mads": "application/mads+xml",
224 "webmanifest": "application/manifest+json",
225 "mrc": "application/marc",
226 "mrcx": "application/marcxml+xml",
227 "ma": "application/mathematica",
228 "nb": "application/mathematica",
229 "mb": "application/mathematica",
230 "mathml": "application/mathml+xml",
231 "mbox": "application/mbox",
232 "mscml": "application/mediaservercontrol+xml",
233 "metalink": "application/metalink+xml",
234 "meta4": "application/metalink4+xml",
235 "mets": "application/mets+xml",
236 "mods": "application/mods+xml",
237 "m21": "application/mp21",
238 "mp21": "application/mp21",
239 "mp4s": "application/mp4",
240 "m4p": "application/mp4",
241 "doc": "application/msword",
242 "dot": "application/msword",
243 "mxf": "application/mxf",
244 "bin": "application/octet-stream",
245 "dms": "application/octet-stream",
246 "lrf": "application/octet-stream",
247 "mar": "application/octet-stream",
248 "so": "application/octet-stream",
249 "dist": "application/octet-stream",
250 "distz": "application/octet-stream",
251 "pkg": "application/octet-stream",
252 "bpk": "application/octet-stream",
253 "dump": "application/octet-stream",
254 "elc": "application/octet-stream",
255 "deploy": "application/octet-stream",
256 "exe": "application/x-msdownload",
257 "dll": "application/x-msdownload",
258 "deb": "application/x-debian-package",
259 "dmg": "application/x-apple-diskimage",
260 "iso": "application/x-iso9660-image",
261 "img": "application/octet-stream",
262 "msi": "application/x-msdownload",
263 "msp": "application/octet-stream",
264 "msm": "application/octet-stream",
265 "buffer": "application/octet-stream",
266 "oda": "application/oda",
267 "opf": "application/oebps-package+xml",
268 "ogx": "application/ogg",
269 "omdoc": "application/omdoc+xml",
270 "onetoc": "application/onenote",
271 "onetoc2": "application/onenote",
272 "onetmp": "application/onenote",
273 "onepkg": "application/onenote",
274 "oxps": "application/oxps",
275 "xer": "application/patch-ops-error+xml",
276 "pdf": "application/pdf",
277 "pgp": "application/pgp-encrypted",
278 "asc": "application/pgp-signature",
279 "sig": "application/pgp-signature",
280 "prf": "application/pics-rules",
281 "p10": "application/pkcs10",
282 "p7m": "application/pkcs7-mime",
283 "p7c": "application/pkcs7-mime",
284 "p7s": "application/pkcs7-signature",
285 "p8": "application/pkcs8",
286 "ac": "application/pkix-attr-cert",
287 "cer": "application/pkix-cert",
288 "crl": "application/pkix-crl",
289 "pkipath": "application/pkix-pkipath",
290 "pki": "application/pkixcmp",
291 "pls": "application/pls+xml",
292 "ai": "application/postscript",
293 "eps": "application/postscript",
294 "ps": "application/postscript",
295 "cww": "application/prs.cww",
296 "pskcxml": "application/pskc+xml",
297 "rdf": "application/rdf+xml",
298 "rif": "application/reginfo+xml",
299 "rnc": "application/relax-ng-compact-syntax",
300 "rl": "application/resource-lists+xml",
301 "rld": "application/resource-lists-diff+xml",
302 "rs": "application/rls-services+xml",
303 "gbr": "application/rpki-ghostbusters",
304 "mft": "application/rpki-manifest",
305 "roa": "application/rpki-roa",
306 "rsd": "application/rsd+xml",
307 "rss": "application/rss+xml",
308 "rtf": "text/rtf",
309 "sbml": "application/sbml+xml",
310 "scq": "application/scvp-cv-request",
311 "scs": "application/scvp-cv-response",
312 "spq": "application/scvp-vp-request",
313 "spp": "application/scvp-vp-response",
314 "sdp": "application/sdp",
315 "setpay": "application/set-payment-initiation",
316 "setreg": "application/set-registration-initiation",
317 "shf": "application/shf+xml",
318 "smi": "application/smil+xml",
319 "smil": "application/smil+xml",
320 "rq": "application/sparql-query",
321 "srx": "application/sparql-results+xml",
322 "gram": "application/srgs",
323 "grxml": "application/srgs+xml",
324 "sru": "application/sru+xml",
325 "ssdl": "application/ssdl+xml",
326 "ssml": "application/ssml+xml",
327 "tei": "application/tei+xml",
328 "teicorpus": "application/tei+xml",
329 "tfi": "application/thraud+xml",
330 "tsd": "application/timestamped-data",
331 "plb": "application/vnd.3gpp.pic-bw-large",
332 "psb": "application/vnd.3gpp.pic-bw-small",
333 "pvb": "application/vnd.3gpp.pic-bw-var",
334 "tcap": "application/vnd.3gpp2.tcap",
335 "pwn": "application/vnd.3m.post-it-notes",
336 "aso": "application/vnd.accpac.simply.aso",
337 "imp": "application/vnd.accpac.simply.imp",
338 "acu": "application/vnd.acucobol",
339 "atc": "application/vnd.acucorp",
340 "acutc": "application/vnd.acucorp",
341 "air": "application/vnd.adobe.air-application-installer-package+zip",
342 "fcdt": "application/vnd.adobe.formscentral.fcdt",
343 "fxp": "application/vnd.adobe.fxp",
344 "fxpl": "application/vnd.adobe.fxp",
345 "xdp": "application/vnd.adobe.xdp+xml",
346 "xfdf": "application/vnd.adobe.xfdf",
347 "ahead": "application/vnd.ahead.space",
348 "azf": "application/vnd.airzip.filesecure.azf",
349 "azs": "application/vnd.airzip.filesecure.azs",
350 "azw": "application/vnd.amazon.ebook",
351 "acc": "application/vnd.americandynamics.acc",
352 "ami": "application/vnd.amiga.ami",
353 "apk": "application/vnd.android.package-archive",
354 "cii": "application/vnd.anser-web-certificate-issue-initiation",
355 "fti": "application/vnd.anser-web-funds-transfer-initiation",
356 "atx": "application/vnd.antix.game-component",
357 "mpkg": "application/vnd.apple.installer+xml",
358 "m3u8": "application/vnd.apple.mpegurl",
359 "pkpass": "application/vnd.apple.pkpass",
360 "swi": "application/vnd.aristanetworks.swi",
361 "iota": "application/vnd.astraea-software.iota",
362 "aep": "application/vnd.audiograph",
363 "mpm": "application/vnd.blueice.multipass",
364 "bmi": "application/vnd.bmi",
365 "rep": "application/vnd.businessobjects",
366 "cdxml": "application/vnd.chemdraw+xml",
367 "mmd": "application/vnd.chipnuts.karaoke-mmd",
368 "cdy": "application/vnd.cinderella",
369 "cla": "application/vnd.claymore",
370 "rp9": "application/vnd.cloanto.rp9",
371 "c4g": "application/vnd.clonk.c4group",
372 "c4d": "application/vnd.clonk.c4group",
373 "c4f": "application/vnd.clonk.c4group",
374 "c4p": "application/vnd.clonk.c4group",
375 "c4u": "application/vnd.clonk.c4group",
376 "c11amc": "application/vnd.cluetrust.cartomobile-config",
377 "c11amz": "application/vnd.cluetrust.cartomobile-config-pkg",
378 "csp": "application/vnd.commonspace",
379 "cdbcmsg": "application/vnd.contact.cmsg",
380 "cmc": "application/vnd.cosmocaller",
381 "clkx": "application/vnd.crick.clicker",
382 "clkk": "application/vnd.crick.clicker.keyboard",
383 "clkp": "application/vnd.crick.clicker.palette",
384 "clkt": "application/vnd.crick.clicker.template",
385 "clkw": "application/vnd.crick.clicker.wordbank",
386 "wbs": "application/vnd.criticaltools.wbs+xml",
387 "pml": "application/vnd.ctc-posml",
388 "ppd": "application/vnd.cups-ppd",
389 "car": "application/vnd.curl.car",
390 "pcurl": "application/vnd.curl.pcurl",
391 "dart": "application/vnd.dart",
392 "rdz": "application/vnd.data-vision.rdz",
393 "uvf": "application/vnd.dece.data",
394 "uvvf": "application/vnd.dece.data",
395 "uvd": "application/vnd.dece.data",
396 "uvvd": "application/vnd.dece.data",
397 "uvt": "application/vnd.dece.ttml+xml",
398 "uvvt": "application/vnd.dece.ttml+xml",
399 "uvx": "application/vnd.dece.unspecified",
400 "uvvx": "application/vnd.dece.unspecified",
401 "uvz": "application/vnd.dece.zip",
402 "uvvz": "application/vnd.dece.zip",
403 "fe_launch": "application/vnd.denovo.fcselayout-link",
404 "dna": "application/vnd.dna",
405 "mlp": "application/vnd.dolby.mlp",
406 "dpg": "application/vnd.dpgraph",
407 "dfac": "application/vnd.dreamfactory",
408 "kpxx": "application/vnd.ds-keypoint",
409 "ait": "application/vnd.dvb.ait",
410 "svc": "application/vnd.dvb.service",
411 "geo": "application/vnd.dynageo",
412 "mag": "application/vnd.ecowin.chart",
413 "nml": "application/vnd.enliven",
414 "esf": "application/vnd.epson.esf",
415 "msf": "application/vnd.epson.msf",
416 "qam": "application/vnd.epson.quickanime",
417 "slt": "application/vnd.epson.salt",
418 "ssf": "application/vnd.epson.ssf",
419 "es3": "application/vnd.eszigno3+xml",
420 "et3": "application/vnd.eszigno3+xml",
421 "ez2": "application/vnd.ezpix-album",
422 "ez3": "application/vnd.ezpix-package",
423 "fdf": "application/vnd.fdf",
424 "mseed": "application/vnd.fdsn.mseed",
425 "seed": "application/vnd.fdsn.seed",
426 "dataless": "application/vnd.fdsn.seed",
427 "gph": "application/vnd.flographit",
428 "ftc": "application/vnd.fluxtime.clip",
429 "fm": "application/vnd.framemaker",
430 "frame": "application/vnd.framemaker",
431 "maker": "application/vnd.framemaker",
432 "book": "application/vnd.framemaker",
433 "fnc": "application/vnd.frogans.fnc",
434 "ltf": "application/vnd.frogans.ltf",
435 "fsc": "application/vnd.fsc.weblaunch",
436 "oas": "application/vnd.fujitsu.oasys",
437 "oa2": "application/vnd.fujitsu.oasys2",
438 "oa3": "application/vnd.fujitsu.oasys3",
439 "fg5": "application/vnd.fujitsu.oasysgp",
440 "bh2": "application/vnd.fujitsu.oasysprs",
441 "ddd": "application/vnd.fujixerox.ddd",
442 "xdw": "application/vnd.fujixerox.docuworks",
443 "xbd": "application/vnd.fujixerox.docuworks.binder",
444 "fzs": "application/vnd.fuzzysheet",
445 "txd": "application/vnd.genomatix.tuxedo",
446 "ggb": "application/vnd.geogebra.file",
447 "ggt": "application/vnd.geogebra.tool",
448 "gex": "application/vnd.geometry-explorer",
449 "gre": "application/vnd.geometry-explorer",
450 "gxt": "application/vnd.geonext",
451 "g2w": "application/vnd.geoplan",
452 "g3w": "application/vnd.geospace",
453 "gmx": "application/vnd.gmx",
454 "gdoc": "application/vnd.google-apps.document",
455 "gslides": "application/vnd.google-apps.presentation",
456 "gsheet": "application/vnd.google-apps.spreadsheet",
457 "kml": "application/vnd.google-earth.kml+xml",
458 "kmz": "application/vnd.google-earth.kmz",
459 "gqf": "application/vnd.grafeq",
460 "gqs": "application/vnd.grafeq",
461 "gac": "application/vnd.groove-account",
462 "ghf": "application/vnd.groove-help",
463 "gim": "application/vnd.groove-identity-message",
464 "grv": "application/vnd.groove-injector",
465 "gtm": "application/vnd.groove-tool-message",
466 "tpl": "application/vnd.groove-tool-template",
467 "vcg": "application/vnd.groove-vcard",
468 "hal": "application/vnd.hal+xml",
469 "zmm": "application/vnd.handheld-entertainment+xml",
470 "hbci": "application/vnd.hbci",
471 "les": "application/vnd.hhe.lesson-player",
472 "hpgl": "application/vnd.hp-hpgl",
473 "hpid": "application/vnd.hp-hpid",
474 "hps": "application/vnd.hp-hps",
475 "jlt": "application/vnd.hp-jlyt",
476 "pcl": "application/vnd.hp-pcl",
477 "pclxl": "application/vnd.hp-pclxl",
478 "sfd-hdstx": "application/vnd.hydrostatix.sof-data",
479 "mpy": "application/vnd.ibm.minipay",
480 "afp": "application/vnd.ibm.modcap",
481 "listafp": "application/vnd.ibm.modcap",
482 "list3820": "application/vnd.ibm.modcap",
483 "irm": "application/vnd.ibm.rights-management",
484 "sc": "application/vnd.ibm.secure-container",
485 "icc": "application/vnd.iccprofile",
486 "icm": "application/vnd.iccprofile",
487 "igl": "application/vnd.igloader",
488 "ivp": "application/vnd.immervision-ivp",
489 "ivu": "application/vnd.immervision-ivu",
490 "igm": "application/vnd.insors.igm",
491 "xpw": "application/vnd.intercon.formnet",
492 "xpx": "application/vnd.intercon.formnet",
493 "i2g": "application/vnd.intergeo",
494 "qbo": "application/vnd.intu.qbo",
495 "qfx": "application/vnd.intu.qfx",
496 "rcprofile": "application/vnd.ipunplugged.rcprofile",
497 "irp": "application/vnd.irepository.package+xml",
498 "xpr": "application/vnd.is-xpr",
499 "fcs": "application/vnd.isac.fcs",
500 "jam": "application/vnd.jam",
501 "rms": "application/vnd.jcp.javame.midlet-rms",
502 "jisp": "application/vnd.jisp",
503 "joda": "application/vnd.joost.joda-archive",
504 "ktz": "application/vnd.kahootz",
505 "ktr": "application/vnd.kahootz",
506 "karbon": "application/vnd.kde.karbon",
507 "chrt": "application/vnd.kde.kchart",
508 "kfo": "application/vnd.kde.kformula",
509 "flw": "application/vnd.kde.kivio",
510 "kon": "application/vnd.kde.kontour",
511 "kpr": "application/vnd.kde.kpresenter",
512 "kpt": "application/vnd.kde.kpresenter",
513 "ksp": "application/vnd.kde.kspread",
514 "kwd": "application/vnd.kde.kword",
515 "kwt": "application/vnd.kde.kword",
516 "htke": "application/vnd.kenameaapp",
517 "kia": "application/vnd.kidspiration",
518 "kne": "application/vnd.kinar",
519 "knp": "application/vnd.kinar",
520 "skp": "application/vnd.koan",
521 "skd": "application/vnd.koan",
522 "skt": "application/vnd.koan",
523 "skm": "application/vnd.koan",
524 "sse": "application/vnd.kodak-descriptor",
525 "lasxml": "application/vnd.las.las+xml",
526 "lbd": "application/vnd.llamagraphics.life-balance.desktop",
527 "lbe": "application/vnd.llamagraphics.life-balance.exchange+xml",
528 "apr": "application/vnd.lotus-approach",
529 "pre": "application/vnd.lotus-freelance",
530 "nsf": "application/vnd.lotus-notes",
531 "org": "application/vnd.lotus-organizer",
532 "scm": "application/vnd.lotus-screencam",
533 "lwp": "application/vnd.lotus-wordpro",
534 "portpkg": "application/vnd.macports.portpkg",
535 "mcd": "application/vnd.mcd",
536 "mc1": "application/vnd.medcalcdata",
537 "cdkey": "application/vnd.mediastation.cdkey",
538 "mwf": "application/vnd.mfer",
539 "mfm": "application/vnd.mfmp",
540 "flo": "application/vnd.micrografx.flo",
541 "igx": "application/vnd.micrografx.igx",
542 "mif": "application/vnd.mif",
543 "daf": "application/vnd.mobius.daf",
544 "dis": "application/vnd.mobius.dis",
545 "mbk": "application/vnd.mobius.mbk",
546 "mqy": "application/vnd.mobius.mqy",
547 "msl": "application/vnd.mobius.msl",
548 "plc": "application/vnd.mobius.plc",
549 "txf": "application/vnd.mobius.txf",
550 "mpn": "application/vnd.mophun.application",
551 "mpc": "application/vnd.mophun.certificate",
552 "xul": "application/vnd.mozilla.xul+xml",
553 "cil": "application/vnd.ms-artgalry",
554 "cab": "application/vnd.ms-cab-compressed",
555 "xls": "application/vnd.ms-excel",
556 "xlm": "application/vnd.ms-excel",
557 "xla": "application/vnd.ms-excel",
558 "xlc": "application/vnd.ms-excel",
559 "xlt": "application/vnd.ms-excel",
560 "xlw": "application/vnd.ms-excel",
561 "xlam": "application/vnd.ms-excel.addin.macroenabled.12",
562 "xlsb": "application/vnd.ms-excel.sheet.binary.macroenabled.12",
563 "xlsm": "application/vnd.ms-excel.sheet.macroenabled.12",
564 "xltm": "application/vnd.ms-excel.template.macroenabled.12",
565 "eot": "application/vnd.ms-fontobject",
566 "chm": "application/vnd.ms-htmlhelp",
567 "ims": "application/vnd.ms-ims",
568 "lrm": "application/vnd.ms-lrm",
569 "thmx": "application/vnd.ms-officetheme",
570 "cat": "application/vnd.ms-pki.seccat",
571 "stl": "application/vnd.ms-pki.stl",
572 "ppt": "application/vnd.ms-powerpoint",
573 "pps": "application/vnd.ms-powerpoint",
574 "pot": "application/vnd.ms-powerpoint",
575 "ppam": "application/vnd.ms-powerpoint.addin.macroenabled.12",
576 "pptm": "application/vnd.ms-powerpoint.presentation.macroenabled.12",
577 "sldm": "application/vnd.ms-powerpoint.slide.macroenabled.12",
578 "ppsm": "application/vnd.ms-powerpoint.slideshow.macroenabled.12",
579 "potm": "application/vnd.ms-powerpoint.template.macroenabled.12",
580 "mpp": "application/vnd.ms-project",
581 "mpt": "application/vnd.ms-project",
582 "docm": "application/vnd.ms-word.document.macroenabled.12",
583 "dotm": "application/vnd.ms-word.template.macroenabled.12",
584 "wps": "application/vnd.ms-works",
585 "wks": "application/vnd.ms-works",
586 "wcm": "application/vnd.ms-works",
587 "wdb": "application/vnd.ms-works",
588 "wpl": "application/vnd.ms-wpl",
589 "xps": "application/vnd.ms-xpsdocument",
590 "mseq": "application/vnd.mseq",
591 "mus": "application/vnd.musician",
592 "msty": "application/vnd.muvee.style",
593 "taglet": "application/vnd.mynfc",
594 "nlu": "application/vnd.neurolanguage.nlu",
595 "ntf": "application/vnd.nitf",
596 "nitf": "application/vnd.nitf",
597 "nnd": "application/vnd.noblenet-directory",
598 "nns": "application/vnd.noblenet-sealer",
599 "nnw": "application/vnd.noblenet-web",
600 "ngdat": "application/vnd.nokia.n-gage.data",
601 "n-gage": "application/vnd.nokia.n-gage.symbian.install",
602 "rpst": "application/vnd.nokia.radio-preset",
603 "rpss": "application/vnd.nokia.radio-presets",
604 "edm": "application/vnd.novadigm.edm",
605 "edx": "application/vnd.novadigm.edx",
606 "ext": "application/vnd.novadigm.ext",
607 "odc": "application/vnd.oasis.opendocument.chart",
608 "otc": "application/vnd.oasis.opendocument.chart-template",
609 "odb": "application/vnd.oasis.opendocument.database",
610 "odf": "application/vnd.oasis.opendocument.formula",
611 "odft": "application/vnd.oasis.opendocument.formula-template",
612 "odg": "application/vnd.oasis.opendocument.graphics",
613 "otg": "application/vnd.oasis.opendocument.graphics-template",
614 "odi": "application/vnd.oasis.opendocument.image",
615 "oti": "application/vnd.oasis.opendocument.image-template",
616 "odp": "application/vnd.oasis.opendocument.presentation",
617 "otp": "application/vnd.oasis.opendocument.presentation-template",
618 "ods": "application/vnd.oasis.opendocument.spreadsheet",
619 "ots": "application/vnd.oasis.opendocument.spreadsheet-template",
620 "odt": "application/vnd.oasis.opendocument.text",
621 "odm": "application/vnd.oasis.opendocument.text-master",
622 "ott": "application/vnd.oasis.opendocument.text-template",
623 "oth": "application/vnd.oasis.opendocument.text-web",
624 "xo": "application/vnd.olpc-sugar",
625 "dd2": "application/vnd.oma.dd2+xml",
626 "oxt": "application/vnd.openofficeorg.extension",
627 "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
628 "sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide",
629 "ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
630 "potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
631 "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
632 "xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
633 "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
634 "dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
635 "mgp": "application/vnd.osgeo.mapguide.package",
636 "dp": "application/vnd.osgi.dp",
637 "esa": "application/vnd.osgi.subsystem",
638 "pdb": "application/x-pilot",
639 "pqa": "application/vnd.palm",
640 "oprc": "application/vnd.palm",
641 "paw": "application/vnd.pawaafile",
642 "str": "application/vnd.pg.format",
643 "ei6": "application/vnd.pg.osasli",
644 "efif": "application/vnd.picsel",
645 "wg": "application/vnd.pmi.widget",
646 "plf": "application/vnd.pocketlearn",
647 "pbd": "application/vnd.powerbuilder6",
648 "box": "application/vnd.previewsystems.box",
649 "mgz": "application/vnd.proteus.magazine",
650 "qps": "application/vnd.publishare-delta-tree",
651 "ptid": "application/vnd.pvi.ptid1",
652 "qxd": "application/vnd.quark.quarkxpress",
653 "qxt": "application/vnd.quark.quarkxpress",
654 "qwd": "application/vnd.quark.quarkxpress",
655 "qwt": "application/vnd.quark.quarkxpress",
656 "qxl": "application/vnd.quark.quarkxpress",
657 "qxb": "application/vnd.quark.quarkxpress",
658 "bed": "application/vnd.realvnc.bed",
659 "mxl": "application/vnd.recordare.musicxml",
660 "musicxml": "application/vnd.recordare.musicxml+xml",
661 "cryptonote": "application/vnd.rig.cryptonote",
662 "cod": "application/vnd.rim.cod",
663 "rm": "application/vnd.rn-realmedia",
664 "rmvb": "application/vnd.rn-realmedia-vbr",
665 "link66": "application/vnd.route66.link66+xml",
666 "st": "application/vnd.sailingtracker.track",
667 "see": "application/vnd.seemail",
668 "sema": "application/vnd.sema",
669 "semd": "application/vnd.semd",
670 "semf": "application/vnd.semf",
671 "ifm": "application/vnd.shana.informed.formdata",
672 "itp": "application/vnd.shana.informed.formtemplate",
673 "iif": "application/vnd.shana.informed.interchange",
674 "ipk": "application/vnd.shana.informed.package",
675 "twd": "application/vnd.simtech-mindmapper",
676 "twds": "application/vnd.simtech-mindmapper",
677 "mmf": "application/vnd.smaf",
678 "teacher": "application/vnd.smart.teacher",
679 "sdkm": "application/vnd.solent.sdkm+xml",
680 "sdkd": "application/vnd.solent.sdkm+xml",
681 "dxp": "application/vnd.spotfire.dxp",
682 "sfs": "application/vnd.spotfire.sfs",
683 "sdc": "application/vnd.stardivision.calc",
684 "sda": "application/vnd.stardivision.draw",
685 "sdd": "application/vnd.stardivision.impress",
686 "smf": "application/vnd.stardivision.math",
687 "sdw": "application/vnd.stardivision.writer",
688 "vor": "application/vnd.stardivision.writer",
689 "sgl": "application/vnd.stardivision.writer-global",
690 "smzip": "application/vnd.stepmania.package",
691 "sm": "application/vnd.stepmania.stepchart",
692 "sxc": "application/vnd.sun.xml.calc",
693 "stc": "application/vnd.sun.xml.calc.template",
694 "sxd": "application/vnd.sun.xml.draw",
695 "std": "application/vnd.sun.xml.draw.template",
696 "sxi": "application/vnd.sun.xml.impress",
697 "sti": "application/vnd.sun.xml.impress.template",
698 "sxm": "application/vnd.sun.xml.math",
699 "sxw": "application/vnd.sun.xml.writer",
700 "sxg": "application/vnd.sun.xml.writer.global",
701 "stw": "application/vnd.sun.xml.writer.template",
702 "sus": "application/vnd.sus-calendar",
703 "susp": "application/vnd.sus-calendar",
704 "svd": "application/vnd.svd",
705 "sis": "application/vnd.symbian.install",
706 "sisx": "application/vnd.symbian.install",
707 "xsm": "application/vnd.syncml+xml",
708 "bdm": "application/vnd.syncml.dm+wbxml",
709 "xdm": "application/vnd.syncml.dm+xml",
710 "tao": "application/vnd.tao.intent-module-archive",
711 "pcap": "application/vnd.tcpdump.pcap",
712 "cap": "application/vnd.tcpdump.pcap",
713 "dmp": "application/vnd.tcpdump.pcap",
714 "tmo": "application/vnd.tmobile-livetv",
715 "tpt": "application/vnd.trid.tpt",
716 "mxs": "application/vnd.triscape.mxs",
717 "tra": "application/vnd.trueapp",
718 "ufd": "application/vnd.ufdl",
719 "ufdl": "application/vnd.ufdl",
720 "utz": "application/vnd.uiq.theme",
721 "umj": "application/vnd.umajin",
722 "unityweb": "application/vnd.unity",
723 "uoml": "application/vnd.uoml+xml",
724 "vcx": "application/vnd.vcx",
725 "vsd": "application/vnd.visio",
726 "vst": "application/vnd.visio",
727 "vss": "application/vnd.visio",
728 "vsw": "application/vnd.visio",
729 "vis": "application/vnd.visionary",
730 "vsf": "application/vnd.vsf",
731 "wbxml": "application/vnd.wap.wbxml",
732 "wmlc": "application/vnd.wap.wmlc",
733 "wmlsc": "application/vnd.wap.wmlscriptc",
734 "wtb": "application/vnd.webturbo",
735 "nbp": "application/vnd.wolfram.player",
736 "wpd": "application/vnd.wordperfect",
737 "wqd": "application/vnd.wqd",
738 "stf": "application/vnd.wt.stf",
739 "xar": "application/vnd.xara",
740 "xfdl": "application/vnd.xfdl",
741 "hvd": "application/vnd.yamaha.hv-dic",
742 "hvs": "application/vnd.yamaha.hv-script",
743 "hvp": "application/vnd.yamaha.hv-voice",
744 "osf": "application/vnd.yamaha.openscoreformat",
745 "osfpvg": "application/vnd.yamaha.openscoreformat.osfpvg+xml",
746 "saf": "application/vnd.yamaha.smaf-audio",
747 "spf": "application/vnd.yamaha.smaf-phrase",
748 "cmp": "application/vnd.yellowriver-custom-menu",
749 "zir": "application/vnd.zul",
750 "zirz": "application/vnd.zul",
751 "zaz": "application/vnd.zzazz.deck+xml",
752 "vxml": "application/voicexml+xml",
753 "wgt": "application/widget",
754 "hlp": "application/winhlp",
755 "wsdl": "application/wsdl+xml",
756 "wspolicy": "application/wspolicy+xml",
757 "7z": "application/x-7z-compressed",
758 "abw": "application/x-abiword",
759 "ace": "application/x-ace-compressed",
760 "aab": "application/x-authorware-bin",
761 "x32": "application/x-authorware-bin",
762 "u32": "application/x-authorware-bin",
763 "vox": "application/x-authorware-bin",
764 "aam": "application/x-authorware-map",
765 "aas": "application/x-authorware-seg",
766 "bcpio": "application/x-bcpio",
767 "torrent": "application/x-bittorrent",
768 "blb": "application/x-blorb",
769 "blorb": "application/x-blorb",
770 "bz": "application/x-bzip",
771 "bz2": "application/x-bzip2",
772 "boz": "application/x-bzip2",
773 "cbr": "application/x-cbr",
774 "cba": "application/x-cbr",
775 "cbt": "application/x-cbr",
776 "cbz": "application/x-cbr",
777 "cb7": "application/x-cbr",
778 "vcd": "application/x-cdlink",
779 "cfs": "application/x-cfs-compressed",
780 "chat": "application/x-chat",
781 "pgn": "application/x-chess-pgn",
782 "crx": "application/x-chrome-extension",
783 "cco": "application/x-cocoa",
784 "nsc": "application/x-conference",
785 "cpio": "application/x-cpio",
786 "csh": "application/x-csh",
787 "udeb": "application/x-debian-package",
788 "dgc": "application/x-dgc-compressed",
789 "dir": "application/x-director",
790 "dcr": "application/x-director",
791 "dxr": "application/x-director",
792 "cst": "application/x-director",
793 "cct": "application/x-director",
794 "cxt": "application/x-director",
795 "w3d": "application/x-director",
796 "fgd": "application/x-director",
797 "swa": "application/x-director",
798 "wad": "application/x-doom",
799 "ncx": "application/x-dtbncx+xml",
800 "dtb": "application/x-dtbook+xml",
801 "res": "application/x-dtbresource+xml",
802 "dvi": "application/x-dvi",
803 "evy": "application/x-envoy",
804 "eva": "application/x-eva",
805 "bdf": "application/x-font-bdf",
806 "gsf": "application/x-font-ghostscript",
807 "psf": "application/x-font-linux-psf",
808 "otf": "font/opentype",
809 "pcf": "application/x-font-pcf",
810 "snf": "application/x-font-snf",
811 "ttf": "application/x-font-ttf",
812 "ttc": "application/x-font-ttf",
813 "pfa": "application/x-font-type1",
814 "pfb": "application/x-font-type1",
815 "pfm": "application/x-font-type1",
816 "afm": "application/x-font-type1",
817 "arc": "application/x-freearc",
818 "spl": "application/x-futuresplash",
819 "gca": "application/x-gca-compressed",
820 "ulx": "application/x-glulx",
821 "gnumeric": "application/x-gnumeric",
822 "gramps": "application/x-gramps-xml",
823 "gtar": "application/x-gtar",
824 "hdf": "application/x-hdf",
825 "php": "application/x-httpd-php",
826 "install": "application/x-install-instructions",
827 "jardiff": "application/x-java-archive-diff",
828 "jnlp": "application/x-java-jnlp-file",
829 "latex": "application/x-latex",
830 "luac": "application/x-lua-bytecode",
831 "lzh": "application/x-lzh-compressed",
832 "lha": "application/x-lzh-compressed",
833 "run": "application/x-makeself",
834 "mie": "application/x-mie",
835 "prc": "application/x-pilot",
836 "mobi": "application/x-mobipocket-ebook",
837 "application": "application/x-ms-application",
838 "lnk": "application/x-ms-shortcut",
839 "wmd": "application/x-ms-wmd",
840 "wmz": "application/x-msmetafile",
841 "xbap": "application/x-ms-xbap",
842 "mdb": "application/x-msaccess",
843 "obd": "application/x-msbinder",
844 "crd": "application/x-mscardfile",
845 "clp": "application/x-msclip",
846 "com": "application/x-msdownload",
847 "bat": "application/x-msdownload",
848 "mvb": "application/x-msmediaview",
849 "m13": "application/x-msmediaview",
850 "m14": "application/x-msmediaview",
851 "wmf": "application/x-msmetafile",
852 "emf": "application/x-msmetafile",
853 "emz": "application/x-msmetafile",
854 "mny": "application/x-msmoney",
855 "pub": "application/x-mspublisher",
856 "scd": "application/x-msschedule",
857 "trm": "application/x-msterminal",
858 "wri": "application/x-mswrite",
859 "nc": "application/x-netcdf",
860 "cdf": "application/x-netcdf",
861 "pac": "application/x-ns-proxy-autoconfig",
862 "nzb": "application/x-nzb",
863 "pl": "application/x-perl",
864 "pm": "application/x-perl",
865 "p12": "application/x-pkcs12",
866 "pfx": "application/x-pkcs12",
867 "p7b": "application/x-pkcs7-certificates",
868 "spc": "application/x-pkcs7-certificates",
869 "p7r": "application/x-pkcs7-certreqresp",
870 "rar": "application/x-rar-compressed",
871 "rpm": "application/x-redhat-package-manager",
872 "ris": "application/x-research-info-systems",
873 "sea": "application/x-sea",
874 "sh": "application/x-sh",
875 "shar": "application/x-shar",
876 "swf": "application/x-shockwave-flash",
877 "xap": "application/x-silverlight-app",
878 "sql": "application/x-sql",
879 "sit": "application/x-stuffit",
880 "sitx": "application/x-stuffitx",
881 "srt": "application/x-subrip",
882 "sv4cpio": "application/x-sv4cpio",
883 "sv4crc": "application/x-sv4crc",
884 "t3": "application/x-t3vm-image",
885 "gam": "application/x-tads",
886 "tar": "application/x-tar",
887 "tcl": "application/x-tcl",
888 "tk": "application/x-tcl",
889 "tex": "application/x-tex",
890 "tfm": "application/x-tex-tfm",
891 "texinfo": "application/x-texinfo",
892 "texi": "application/x-texinfo",
893 "obj": "application/x-tgif",
894 "ustar": "application/x-ustar",
895 "src": "application/x-wais-source",
896 "webapp": "application/x-web-app-manifest+json",
897 "der": "application/x-x509-ca-cert",
898 "crt": "application/x-x509-ca-cert",
899 "pem": "application/x-x509-ca-cert",
900 "fig": "application/x-xfig",
901 "xlf": "application/x-xliff+xml",
902 "xpi": "application/x-xpinstall",
903 "xz": "application/x-xz",
904 "z1": "application/x-zmachine",
905 "z2": "application/x-zmachine",
906 "z3": "application/x-zmachine",
907 "z4": "application/x-zmachine",
908 "z5": "application/x-zmachine",
909 "z6": "application/x-zmachine",
910 "z7": "application/x-zmachine",
911 "z8": "application/x-zmachine",
912 "xaml": "application/xaml+xml",
913 "xdf": "application/xcap-diff+xml",
914 "xenc": "application/xenc+xml",
915 "xhtml": "application/xhtml+xml",
916 "xht": "application/xhtml+xml",
917 "xml": "text/xml",
918 "xsl": "application/xml",
919 "xsd": "application/xml",
920 "rng": "application/xml",
921 "dtd": "application/xml-dtd",
922 "xop": "application/xop+xml",
923 "xpl": "application/xproc+xml",
924 "xslt": "application/xslt+xml",
925 "xspf": "application/xspf+xml",
926 "mxml": "application/xv+xml",
927 "xhvml": "application/xv+xml",
928 "xvml": "application/xv+xml",
929 "xvm": "application/xv+xml",
930 "yang": "application/yang",
931 "yin": "application/yin+xml",
932 "zip": "application/zip",
933 "3gpp": "video/3gpp",
934 "adp": "audio/adpcm",
935 "au": "audio/basic",
936 "snd": "audio/basic",
937 "mid": "audio/midi",
938 "midi": "audio/midi",
939 "kar": "audio/midi",
940 "rmi": "audio/midi",
941 "mp3": "audio/mpeg",
942 "m4a": "audio/x-m4a",
943 "mp4a": "audio/mp4",
944 "mpga": "audio/mpeg",
945 "mp2": "audio/mpeg",
946 "mp2a": "audio/mpeg",
947 "m2a": "audio/mpeg",
948 "m3a": "audio/mpeg",
949 "oga": "audio/ogg",
950 "ogg": "audio/ogg",
951 "spx": "audio/ogg",
952 "s3m": "audio/s3m",
953 "sil": "audio/silk",
954 "uva": "audio/vnd.dece.audio",
955 "uvva": "audio/vnd.dece.audio",
956 "eol": "audio/vnd.digital-winds",
957 "dra": "audio/vnd.dra",
958 "dts": "audio/vnd.dts",
959 "dtshd": "audio/vnd.dts.hd",
960 "lvp": "audio/vnd.lucent.voice",
961 "pya": "audio/vnd.ms-playready.media.pya",
962 "ecelp4800": "audio/vnd.nuera.ecelp4800",
963 "ecelp7470": "audio/vnd.nuera.ecelp7470",
964 "ecelp9600": "audio/vnd.nuera.ecelp9600",
965 "rip": "audio/vnd.rip",
966 "wav": "audio/x-wav",
967 "weba": "audio/webm",
968 "aac": "audio/x-aac",
969 "aif": "audio/x-aiff",
970 "aiff": "audio/x-aiff",
971 "aifc": "audio/x-aiff",
972 "caf": "audio/x-caf",
973 "flac": "audio/x-flac",
974 "mka": "audio/x-matroska",
975 "m3u": "audio/x-mpegurl",
976 "wax": "audio/x-ms-wax",
977 "wma": "audio/x-ms-wma",
978 "ram": "audio/x-pn-realaudio",
979 "ra": "audio/x-realaudio",
980 "rmp": "audio/x-pn-realaudio-plugin",
981 "xm": "audio/xm",
982 "cdx": "chemical/x-cdx",
983 "cif": "chemical/x-cif",
984 "cmdf": "chemical/x-cmdf",
985 "cml": "chemical/x-cml",
986 "csml": "chemical/x-csml",
987 "xyz": "chemical/x-xyz",
988 "bmp": "image/x-ms-bmp",
989 "cgm": "image/cgm",
990 "g3": "image/g3fax",
991 "gif": "image/gif",
992 "ief": "image/ief",
993 "jpeg": "image/jpeg",
994 "jpg": "image/jpeg",
995 "jpe": "image/jpeg",
996 "ktx": "image/ktx",
997 "png": "image/png",
998 "btif": "image/prs.btif",
999 "sgi": "image/sgi",
1000 "svg": "image/svg+xml",
1001 "svgz": "image/svg+xml",
1002 "tiff": "image/tiff",
1003 "tif": "image/tiff",
1004 "psd": "image/vnd.adobe.photoshop",
1005 "uvi": "image/vnd.dece.graphic",
1006 "uvvi": "image/vnd.dece.graphic",
1007 "uvg": "image/vnd.dece.graphic",
1008 "uvvg": "image/vnd.dece.graphic",
1009 "djvu": "image/vnd.djvu",
1010 "djv": "image/vnd.djvu",
1011 "sub": "text/vnd.dvb.subtitle",
1012 "dwg": "image/vnd.dwg",
1013 "dxf": "image/vnd.dxf",
1014 "fbs": "image/vnd.fastbidsheet",
1015 "fpx": "image/vnd.fpx",
1016 "fst": "image/vnd.fst",
1017 "mmr": "image/vnd.fujixerox.edmics-mmr",
1018 "rlc": "image/vnd.fujixerox.edmics-rlc",
1019 "mdi": "image/vnd.ms-modi",
1020 "wdp": "image/vnd.ms-photo",
1021 "npx": "image/vnd.net-fpx",
1022 "wbmp": "image/vnd.wap.wbmp",
1023 "xif": "image/vnd.xiff",
1024 "webp": "image/webp",
1025 "3ds": "image/x-3ds",
1026 "ras": "image/x-cmu-raster",
1027 "cmx": "image/x-cmx",
1028 "fh": "image/x-freehand",
1029 "fhc": "image/x-freehand",
1030 "fh4": "image/x-freehand",
1031 "fh5": "image/x-freehand",
1032 "fh7": "image/x-freehand",
1033 "ico": "image/x-icon",
1034 "jng": "image/x-jng",
1035 "sid": "image/x-mrsid-image",
1036 "pcx": "image/x-pcx",
1037 "pic": "image/x-pict",
1038 "pct": "image/x-pict",
1039 "pnm": "image/x-portable-anymap",
1040 "pbm": "image/x-portable-bitmap",
1041 "pgm": "image/x-portable-graymap",
1042 "ppm": "image/x-portable-pixmap",
1043 "rgb": "image/x-rgb",
1044 "tga": "image/x-tga",
1045 "xbm": "image/x-xbitmap",
1046 "xpm": "image/x-xpixmap",
1047 "xwd": "image/x-xwindowdump",
1048 "eml": "message/rfc822",
1049 "mime": "message/rfc822",
1050 "igs": "model/iges",
1051 "iges": "model/iges",
1052 "msh": "model/mesh",
1053 "mesh": "model/mesh",
1054 "silo": "model/mesh",
1055 "dae": "model/vnd.collada+xml",
1056 "dwf": "model/vnd.dwf",
1057 "gdl": "model/vnd.gdl",
1058 "gtw": "model/vnd.gtw",
1059 "mts": "model/vnd.mts",
1060 "vtu": "model/vnd.vtu",
1061 "wrl": "model/vrml",
1062 "vrml": "model/vrml",
1063 "x3db": "model/x3d+binary",
1064 "x3dbz": "model/x3d+binary",
1065 "x3dv": "model/x3d+vrml",
1066 "x3dvz": "model/x3d+vrml",
1067 "x3d": "model/x3d+xml",
1068 "x3dz": "model/x3d+xml",
1069 "appcache": "text/cache-manifest",
1070 "manifest": "text/cache-manifest",
1071 "ics": "text/calendar",
1072 "ifb": "text/calendar",
1073 "coffee": "text/coffeescript",
1074 "litcoffee": "text/coffeescript",
1075 "css": "text/css",
1076 "csv": "text/csv",
1077 "hjson": "text/hjson",
1078 "html": "text/html",
1079 "htm": "text/html",
1080 "shtml": "text/html",
1081 "jade": "text/jade",
1082 "jsx": "text/jsx",
1083 "less": "text/less",
1084 "mml": "text/mathml",
1085 "n3": "text/n3",
1086 "txt": "text/plain",
1087 "text": "text/plain",
1088 "conf": "text/plain",
1089 "def": "text/plain",
1090 "list": "text/plain",
1091 "log": "text/plain",
1092 "in": "text/plain",
1093 "ini": "text/plain",
1094 "dsc": "text/prs.lines.tag",
1095 "rtx": "text/richtext",
1096 "sgml": "text/sgml",
1097 "sgm": "text/sgml",
1098 "slim": "text/slim",
1099 "slm": "text/slim",
1100 "stylus": "text/stylus",
1101 "styl": "text/stylus",
1102 "tsv": "text/tab-separated-values",
1103 "t": "text/troff",
1104 "tr": "text/troff",
1105 "roff": "text/troff",
1106 "man": "text/troff",
1107 "me": "text/troff",
1108 "ms": "text/troff",
1109 "ttl": "text/turtle",
1110 "uri": "text/uri-list",
1111 "uris": "text/uri-list",
1112 "urls": "text/uri-list",
1113 "vcard": "text/vcard",
1114 "curl": "text/vnd.curl",
1115 "dcurl": "text/vnd.curl.dcurl",
1116 "mcurl": "text/vnd.curl.mcurl",
1117 "scurl": "text/vnd.curl.scurl",
1118 "fly": "text/vnd.fly",
1119 "flx": "text/vnd.fmi.flexstor",
1120 "gv": "text/vnd.graphviz",
1121 "3dml": "text/vnd.in3d.3dml",
1122 "spot": "text/vnd.in3d.spot",
1123 "jad": "text/vnd.sun.j2me.app-descriptor",
1124 "wml": "text/vnd.wap.wml",
1125 "wmls": "text/vnd.wap.wmlscript",
1126 "vtt": "text/vtt",
1127 "s": "text/x-asm",
1128 "asm": "text/x-asm",
1129 "c": "text/x-c",
1130 "cc": "text/x-c",
1131 "cxx": "text/x-c",
1132 "cpp": "text/x-c",
1133 "h": "text/x-c",
1134 "hh": "text/x-c",
1135 "dic": "text/x-c",
1136 "htc": "text/x-component",
1137 "f": "text/x-fortran",
1138 "for": "text/x-fortran",
1139 "f77": "text/x-fortran",
1140 "f90": "text/x-fortran",
1141 "hbs": "text/x-handlebars-template",
1142 "java": "text/x-java-source",
1143 "lua": "text/x-lua",
1144 "markdown": "text/x-markdown",
1145 "md": "text/x-markdown",
1146 "mkd": "text/x-markdown",
1147 "nfo": "text/x-nfo",
1148 "opml": "text/x-opml",
1149 "p": "text/x-pascal",
1150 "pas": "text/x-pascal",
1151 "pde": "text/x-processing",
1152 "sass": "text/x-sass",
1153 "scss": "text/x-scss",
1154 "etx": "text/x-setext",
1155 "sfv": "text/x-sfv",
1156 "ymp": "text/x-suse-ymp",
1157 "uu": "text/x-uuencode",
1158 "vcs": "text/x-vcalendar",
1159 "vcf": "text/x-vcard",
1160 "yaml": "text/yaml",
1161 "yml": "text/yaml",
1162 "3gp": "video/3gpp",
1163 "3g2": "video/3gpp2",
1164 "h261": "video/h261",
1165 "h263": "video/h263",
1166 "h264": "video/h264",
1167 "jpgv": "video/jpeg",
1168 "jpm": "video/jpm",
1169 "jpgm": "video/jpm",
1170 "mj2": "video/mj2",
1171 "mjp2": "video/mj2",
1172 "ts": "video/mp2t",
1173 "mp4": "video/mp4",
1174 "mp4v": "video/mp4",
1175 "mpg4": "video/mp4",
1176 "mpeg": "video/mpeg",
1177 "mpg": "video/mpeg",
1178 "mpe": "video/mpeg",
1179 "m1v": "video/mpeg",
1180 "m2v": "video/mpeg",
1181 "ogv": "video/ogg",
1182 "qt": "video/quicktime",
1183 "mov": "video/quicktime",
1184 "uvh": "video/vnd.dece.hd",
1185 "uvvh": "video/vnd.dece.hd",
1186 "uvm": "video/vnd.dece.mobile",
1187 "uvvm": "video/vnd.dece.mobile",
1188 "uvp": "video/vnd.dece.pd",
1189 "uvvp": "video/vnd.dece.pd",
1190 "uvs": "video/vnd.dece.sd",
1191 "uvvs": "video/vnd.dece.sd",
1192 "uvv": "video/vnd.dece.video",
1193 "uvvv": "video/vnd.dece.video",
1194 "dvb": "video/vnd.dvb.file",
1195 "fvt": "video/vnd.fvt",
1196 "mxu": "video/vnd.mpegurl",
1197 "m4u": "video/vnd.mpegurl",
1198 "pyv": "video/vnd.ms-playready.media.pyv",
1199 "uvu": "video/vnd.uvvu.mp4",
1200 "uvvu": "video/vnd.uvvu.mp4",
1201 "viv": "video/vnd.vivo",
1202 "webm": "video/webm",
1203 "f4v": "video/x-f4v",
1204 "fli": "video/x-fli",
1205 "flv": "video/x-flv",
1206 "m4v": "video/x-m4v",
1207 "mkv": "video/x-matroska",
1208 "mk3d": "video/x-matroska",
1209 "mks": "video/x-matroska",
1210 "mng": "video/x-mng",
1211 "asf": "video/x-ms-asf",
1212 "asx": "video/x-ms-asf",
1213 "vob": "video/x-ms-vob",
1214 "wm": "video/x-ms-wm",
1215 "wmv": "video/x-ms-wmv",
1216 "wmx": "video/x-ms-wmx",
1217 "wvx": "video/x-ms-wvx",
1218 "avi": "video/x-msvideo",
1219 "movie": "video/x-sgi-movie",
1220 "smv": "video/x-smv",
1221 "ice": "x-conference/x-cooltalk"
1222 };
1223 let mimeOfBuffer;
1224 (() => {
1225 mimeOfBuffer = function(input) {
1226 const buf = new Uint8Array(input);
1227
1228 if (!(buf && buf.length > 1))
1229 return null;
1230
1231
1232 if (buf[0] === 0xFF && buf[1] === 0xD8 && buf[2] === 0xFF) {
1233 return {
1234 ext: 'jpg',
1235 mime: 'image/jpeg',
1236 };
1237 }
1238
1239 if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4E && buf[3] === 0x47) {
1240 return {
1241 ext: 'png',
1242 mime: 'image/png',
1243 };
1244 }
1245
1246 if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46) {
1247 return {
1248 ext: 'gif',
1249 mime: 'image/gif',
1250 };
1251 }
1252
1253 if (buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) {
1254 return {
1255 ext: 'webp',
1256 mime: 'image/webp',
1257 };
1258 }
1259
1260 if (buf[0] === 0x46 && buf[1] === 0x4C && buf[2] === 0x49 && buf[3] === 0x46) {
1261 return {
1262 ext: 'flif',
1263 mime: 'image/flif',
1264 };
1265 }
1266
1267 // needs to be before `tif` check
1268 if (
1269 ((buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0x2A && buf[3] === 0x0) ||
1270 (buf[0] === 0x4D && buf[1] === 0x4D && buf[2] === 0x0 && buf[3] === 0x2A)) && buf[8] === 0x43 && buf[9] === 0x52
1271 ) {
1272 return {
1273 ext: 'cr2',
1274 mime: 'image/x-canon-cr2',
1275 };
1276 }
1277
1278 if (
1279 (buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0x2A && buf[3] === 0x0) ||
1280 (buf[0] === 0x4D && buf[1] === 0x4D && buf[2] === 0x0 && buf[3] === 0x2A)
1281 ) {
1282 return {
1283 ext: 'tif',
1284 mime: 'image/tiff',
1285 };
1286 }
1287
1288 if (buf[0] === 0x42 && buf[1] === 0x4D) {
1289 return {
1290 ext: 'bmp',
1291 mime: 'image/bmp',
1292 };
1293 }
1294
1295 if (buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0xBC) {
1296 return {
1297 ext: 'jxr',
1298 mime: 'image/vnd.ms-photo',
1299 };
1300 }
1301
1302 if (buf[0] === 0x38 && buf[1] === 0x42 && buf[2] === 0x50 && buf[3] === 0x53) {
1303 return {
1304 ext: 'psd',
1305 mime: 'image/vnd.adobe.photoshop',
1306 };
1307 }
1308
1309 // needs to be before `zip` check
1310 if (
1311 buf[0] === 0x50 && buf[1] === 0x4B && buf[2] === 0x3 && buf[3] === 0x4 && buf[30] === 0x6D && buf[31] === 0x69 &&
1312 buf[32] === 0x6D && buf[33] === 0x65 && buf[34] === 0x74 && buf[35] === 0x79 && buf[36] === 0x70 &&
1313 buf[37] === 0x65 && buf[38] === 0x61 && buf[39] === 0x70 && buf[40] === 0x70 && buf[41] === 0x6C &&
1314 buf[42] === 0x69 && buf[43] === 0x63 && buf[44] === 0x61 && buf[45] === 0x74 && buf[46] === 0x69 &&
1315 buf[47] === 0x6F && buf[48] === 0x6E && buf[49] === 0x2F && buf[50] === 0x65 && buf[51] === 0x70 &&
1316 buf[52] === 0x75 && buf[53] === 0x62 && buf[54] === 0x2B && buf[55] === 0x7A && buf[56] === 0x69 &&
1317 buf[57] === 0x70
1318 ) {
1319 return {
1320 ext: 'epub',
1321 mime: 'application/epub+zip',
1322 };
1323 }
1324
1325 // needs to be before `zip` check
1326 // assumes signed .xpi from addons.mozilla.org
1327 if (
1328 buf[0] === 0x50 && buf[1] === 0x4B && buf[2] === 0x3 && buf[3] === 0x4 && buf[30] === 0x4D && buf[31] === 0x45 &&
1329 buf[32] === 0x54 && buf[33] === 0x41 && buf[34] === 0x2D && buf[35] === 0x49 && buf[36] === 0x4E &&
1330 buf[37] === 0x46 && buf[38] === 0x2F && buf[39] === 0x6D && buf[40] === 0x6F && buf[41] === 0x7A &&
1331 buf[42] === 0x69 && buf[43] === 0x6C && buf[44] === 0x6C && buf[45] === 0x61 && buf[46] === 0x2E &&
1332 buf[47] === 0x72 && buf[48] === 0x73 && buf[49] === 0x61
1333 ) {
1334 return {
1335 ext: 'xpi',
1336 mime: 'application/x-xpinstall',
1337 };
1338 }
1339
1340 if (
1341 buf[0] === 0x50 && buf[1] === 0x4B && (buf[2] === 0x3 || buf[2] === 0x5 || buf[2] === 0x7) &&
1342 (buf[3] === 0x4 || buf[3] === 0x6 || buf[3] === 0x8)
1343 ) {
1344 return {
1345 ext: 'zip',
1346 mime: 'application/zip',
1347 };
1348 }
1349
1350 if (buf[257] === 0x75 && buf[258] === 0x73 && buf[259] === 0x74 && buf[260] === 0x61 && buf[261] === 0x72) {
1351 return {
1352 ext: 'tar',
1353 mime: 'application/x-tar',
1354 };
1355 }
1356
1357 if (
1358 buf[0] === 0x52 && buf[1] === 0x61 && buf[2] === 0x72 && buf[3] === 0x21 && buf[4] === 0x1A && buf[5] === 0x7 &&
1359 (buf[6] === 0x0 || buf[6] === 0x1)
1360 ) {
1361 return {
1362 ext: 'rar',
1363 mime: 'application/x-rar-compressed',
1364 };
1365 }
1366
1367 if (buf[0] === 0x1F && buf[1] === 0x8B && buf[2] === 0x8) {
1368 return {
1369 ext: 'gz',
1370 mime: 'application/gzip',
1371 };
1372 }
1373
1374 if (buf[0] === 0x42 && buf[1] === 0x5A && buf[2] === 0x68) {
1375 return {
1376 ext: 'bz2',
1377 mime: 'application/x-bzip2',
1378 };
1379 }
1380
1381 if (buf[0] === 0x37 && buf[1] === 0x7A && buf[2] === 0xBC && buf[3] === 0xAF && buf[4] === 0x27 && buf[5] === 0x1C) {
1382 return {
1383 ext: '7z',
1384 mime: 'application/x-7z-compressed',
1385 };
1386 }
1387
1388 if (buf[0] === 0x78 && buf[1] === 0x01) {
1389 return {
1390 ext: 'dmg',
1391 mime: 'application/x-apple-diskimage',
1392 };
1393 }
1394
1395 if (
1396 (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && (buf[3] === 0x18 || buf[3] === 0x20) && buf[4] === 0x66 &&
1397 buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70) ||
1398 (buf[0] === 0x33 && buf[1] === 0x67 && buf[2] === 0x70 && buf[3] === 0x35) ||
1399 (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1C && buf[4] === 0x66 && buf[5] === 0x74 &&
1400 buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x6D && buf[9] === 0x70 && buf[10] === 0x34 &&
1401 buf[11] === 0x32 && buf[16] === 0x6D && buf[17] === 0x70 && buf[18] === 0x34 && buf[19] === 0x31 &&
1402 buf[20] === 0x6D && buf[21] === 0x70 && buf[22] === 0x34 && buf[23] === 0x32 && buf[24] === 0x69 &&
1403 buf[25] === 0x73 && buf[26] === 0x6F && buf[27] === 0x6D) ||
1404 (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1C && buf[4] === 0x66 && buf[5] === 0x74 &&
1405 buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x69 && buf[9] === 0x73 && buf[10] === 0x6F &&
1406 buf[11] === 0x6D) ||
1407 (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1c && buf[4] === 0x66 && buf[5] === 0x74 &&
1408 buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x6D && buf[9] === 0x70 && buf[10] === 0x34 &&
1409 buf[11] === 0x32 && buf[12] === 0x0 && buf[13] === 0x0 && buf[14] === 0x0 && buf[15] === 0x0)
1410 ) {
1411 return {
1412 ext: 'mp4',
1413 mime: 'video/mp4',
1414 };
1415 }
1416
1417 if (
1418 buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1C && buf[4] === 0x66 &&
1419 buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x4D && buf[9] === 0x34 && buf[10] === 0x56
1420 ) {
1421 return {
1422 ext: 'm4v',
1423 mime: 'video/x-m4v',
1424 };
1425 }
1426
1427 if (buf[0] === 0x4D && buf[1] === 0x54 && buf[2] === 0x68 && buf[3] === 0x64) {
1428 return {
1429 ext: 'mid',
1430 mime: 'audio/midi',
1431 };
1432 }
1433
1434 // https://github.com/threatstack/libmagic/blob/master/magic/Magdir/matroska
1435 if (buf[0] === 0x1A && buf[1] === 0x45 && buf[2] === 0xDF && buf[3] === 0xA3) {
1436 const sliced = buf.subarray(4, 4 + 4096);
1437 const idPos = sliced.findIndex((el, i, arr) => arr[i] === 0x42 && arr[i + 1] === 0x82);
1438
1439 if (idPos >= 0) {
1440 const docTypePos = idPos + 3;
1441 const findDocType = (type) => Array.from(type)
1442 .every((c, i) => sliced[docTypePos + i] === c.charCodeAt(0));
1443
1444 if (findDocType('matroska')) {
1445 return {
1446 ext: 'mkv',
1447 mime: 'video/x-matroska',
1448 };
1449 }
1450 if (findDocType('webm')) {
1451 return {
1452 ext: 'webm',
1453 mime: 'video/webm',
1454 };
1455 }
1456 }
1457 }
1458
1459 if (
1460 buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x14 && buf[4] === 0x66 && buf[5] === 0x74 &&
1461 buf[6] === 0x79 && buf[7] === 0x70
1462 ) {
1463 return {
1464 ext: 'mov',
1465 mime: 'video/quicktime',
1466 };
1467 }
1468
1469 if (
1470 buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x41 && buf[9] === 0x56 &&
1471 buf[10] === 0x49
1472 ) {
1473 return {
1474 ext: 'avi',
1475 mime: 'video/x-msvideo',
1476 };
1477 }
1478
1479 if (
1480 buf[0] === 0x30 && buf[1] === 0x26 && buf[2] === 0xB2 && buf[3] === 0x75 && buf[4] === 0x8E && buf[5] === 0x66 &&
1481 buf[6] === 0xCF && buf[7] === 0x11 && buf[8] === 0xA6 && buf[9] === 0xD9
1482 ) {
1483 return {
1484 ext: 'wmv',
1485 mime: 'video/x-ms-wmv',
1486 };
1487 }
1488
1489 if (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x1 && buf[3].toString(16)[0] === 'b') {
1490 return {
1491 ext: 'mpg',
1492 mime: 'video/mpeg',
1493 };
1494 }
1495
1496 if ((buf[0] === 0x49 && buf[1] === 0x44 && buf[2] === 0x33) || (buf[0] === 0xFF && buf[1] === 0xfb)) {
1497 return {
1498 ext: 'mp3',
1499 mime: 'audio/mpeg',
1500 };
1501 }
1502
1503 if ((buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x4D &&
1504 buf[9] === 0x34 && buf[10] === 0x41) || (buf[0] === 0x4D && buf[1] === 0x34 && buf[2] === 0x41 && buf[3] === 0x20)) {
1505 return {
1506 ext: 'm4a',
1507 mime: 'audio/m4a',
1508 };
1509 }
1510
1511 // needs to be before `ogg` check
1512 if (
1513 buf[28] === 0x4F && buf[29] === 0x70 && buf[30] === 0x75 && buf[31] === 0x73 && buf[32] === 0x48 &&
1514 buf[33] === 0x65 && buf[34] === 0x61 && buf[35] === 0x64
1515 ) {
1516 return {
1517 ext: 'opus',
1518 mime: 'audio/opus',
1519 };
1520 }
1521
1522 if (buf[0] === 0x4F && buf[1] === 0x67 && buf[2] === 0x67 && buf[3] === 0x53) {
1523 return {
1524 ext: 'ogg',
1525 mime: 'audio/ogg',
1526 };
1527 }
1528
1529 if (buf[0] === 0x66 && buf[1] === 0x4C && buf[2] === 0x61 && buf[3] === 0x43) {
1530 return {
1531 ext: 'flac',
1532 mime: 'audio/x-flac',
1533 };
1534 }
1535
1536 if (
1537 buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x57 && buf[9] === 0x41 &&
1538 buf[10] === 0x56 && buf[11] === 0x45
1539 ) {
1540 return {
1541 ext: 'wav',
1542 mime: 'audio/x-wav',
1543 };
1544 }
1545
1546 if (buf[0] === 0x23 && buf[1] === 0x21 && buf[2] === 0x41 && buf[3] === 0x4D && buf[4] === 0x52 && buf[5] === 0x0A) {
1547 return {
1548 ext: 'amr',
1549 mime: 'audio/amr',
1550 };
1551 }
1552
1553 if (buf[0] === 0x25 && buf[1] === 0x50 && buf[2] === 0x44 && buf[3] === 0x46) {
1554 return {
1555 ext: 'pdf',
1556 mime: 'application/pdf',
1557 };
1558 }
1559
1560 if (buf[0] === 0x4D && buf[1] === 0x5A) {
1561 return {
1562 ext: 'exe',
1563 mime: 'application/x-msdownload',
1564 };
1565 }
1566
1567 if ((buf[0] === 0x43 || buf[0] === 0x46) && buf[1] === 0x57 && buf[2] === 0x53) {
1568 return {
1569 ext: 'swf',
1570 mime: 'application/x-shockwave-flash',
1571 };
1572 }
1573
1574 if (buf[0] === 0x7B && buf[1] === 0x5C && buf[2] === 0x72 && buf[3] === 0x74 && buf[4] === 0x66) {
1575 return {
1576 ext: 'rtf',
1577 mime: 'application/rtf',
1578 };
1579 }
1580
1581 if (
1582 (buf[0] === 0x77 && buf[1] === 0x4F && buf[2] === 0x46 && buf[3] === 0x46) &&
1583 (
1584 (buf[4] === 0x00 && buf[5] === 0x01 && buf[6] === 0x00 && buf[7] === 0x00) ||
1585 (buf[4] === 0x4F && buf[5] === 0x54 && buf[6] === 0x54 && buf[7] === 0x4F)
1586 )
1587 ) {
1588 return {
1589 ext: 'woff',
1590 mime: 'application/font-woff',
1591 };
1592 }
1593
1594 if (
1595 (buf[0] === 0x77 && buf[1] === 0x4F && buf[2] === 0x46 && buf[3] === 0x32) &&
1596 (
1597 (buf[4] === 0x00 && buf[5] === 0x01 && buf[6] === 0x00 && buf[7] === 0x00) ||
1598 (buf[4] === 0x4F && buf[5] === 0x54 && buf[6] === 0x54 && buf[7] === 0x4F)
1599 )
1600 ) {
1601 return {
1602 ext: 'woff2',
1603 mime: 'application/font-woff',
1604 };
1605 }
1606
1607 if (
1608 (buf[34] === 0x4C && buf[35] === 0x50) &&
1609 (
1610 (buf[8] === 0x00 && buf[9] === 0x00 && buf[10] === 0x01) ||
1611 (buf[8] === 0x01 && buf[9] === 0x00 && buf[10] === 0x02) ||
1612 (buf[8] === 0x02 && buf[9] === 0x00 && buf[10] === 0x02)
1613 )
1614 ) {
1615 return {
1616 ext: 'eot',
1617 mime: 'application/octet-stream',
1618 };
1619 }
1620
1621 if (buf[0] === 0x00 && buf[1] === 0x01 && buf[2] === 0x00 && buf[3] === 0x00 && buf[4] === 0x00) {
1622 return {
1623 ext: 'ttf',
1624 mime: 'application/font-sfnt',
1625 };
1626 }
1627
1628 if (buf[0] === 0x4F && buf[1] === 0x54 && buf[2] === 0x54 && buf[3] === 0x4F && buf[4] === 0x00) {
1629 return {
1630 ext: 'otf',
1631 mime: 'application/font-sfnt',
1632 };
1633 }
1634
1635 if (buf[0] === 0x00 && buf[1] === 0x00 && buf[2] === 0x01 && buf[3] === 0x00) {
1636 return {
1637 ext: 'ico',
1638 mime: 'image/x-icon',
1639 };
1640 }
1641
1642 if (buf[0] === 0x46 && buf[1] === 0x4C && buf[2] === 0x56 && buf[3] === 0x01) {
1643 return {
1644 ext: 'flv',
1645 mime: 'video/x-flv',
1646 };
1647 }
1648
1649 if (buf[0] === 0x25 && buf[1] === 0x21) {
1650 return {
1651 ext: 'ps',
1652 mime: 'application/postscript',
1653 };
1654 }
1655
1656 if (buf[0] === 0xFD && buf[1] === 0x37 && buf[2] === 0x7A && buf[3] === 0x58 && buf[4] === 0x5A && buf[5] === 0x00) {
1657 return {
1658 ext: 'xz',
1659 mime: 'application/x-xz',
1660 };
1661 }
1662
1663 if (buf[0] === 0x53 && buf[1] === 0x51 && buf[2] === 0x4C && buf[3] === 0x69) {
1664 return {
1665 ext: 'sqlite',
1666 mime: 'application/x-sqlite3',
1667 };
1668 }
1669
1670 if (buf[0] === 0x4E && buf[1] === 0x45 && buf[2] === 0x53 && buf[3] === 0x1A) {
1671 return {
1672 ext: 'nes',
1673 mime: 'application/x-nintendo-nes-rom',
1674 };
1675 }
1676
1677 if (buf[0] === 0x43 && buf[1] === 0x72 && buf[2] === 0x32 && buf[3] === 0x34) {
1678 return {
1679 ext: 'crx',
1680 mime: 'application/x-google-chrome-extension',
1681 };
1682 }
1683
1684 if (
1685 (buf[0] === 0x4D && buf[1] === 0x53 && buf[2] === 0x43 && buf[3] === 0x46) ||
1686 (buf[0] === 0x49 && buf[1] === 0x53 && buf[2] === 0x63 && buf[3] === 0x28)
1687 ) {
1688 return {
1689 ext: 'cab',
1690 mime: 'application/vnd.ms-cab-compressed',
1691 };
1692 }
1693
1694 // needs to be before `ar` check
1695 if (
1696 buf[0] === 0x21 && buf[1] === 0x3C && buf[2] === 0x61 && buf[3] === 0x72 && buf[4] === 0x63 && buf[5] === 0x68 &&
1697 buf[6] === 0x3E && buf[7] === 0x0A && buf[8] === 0x64 && buf[9] === 0x65 && buf[10] === 0x62 && buf[11] === 0x69 &&
1698 buf[12] === 0x61 && buf[13] === 0x6E && buf[14] === 0x2D && buf[15] === 0x62 && buf[16] === 0x69 &&
1699 buf[17] === 0x6E && buf[18] === 0x61 && buf[19] === 0x72 && buf[20] === 0x79
1700 ) {
1701 return {
1702 ext: 'deb',
1703 mime: 'application/x-deb',
1704 };
1705 }
1706
1707 if (
1708 buf[0] === 0x21 && buf[1] === 0x3C && buf[2] === 0x61 && buf[3] === 0x72 && buf[4] === 0x63 && buf[5] === 0x68 &&
1709 buf[6] === 0x3E
1710 ) {
1711 return {
1712 ext: 'ar',
1713 mime: 'application/x-unix-archive',
1714 };
1715 }
1716
1717 if (buf[0] === 0xED && buf[1] === 0xAB && buf[2] === 0xEE && buf[3] === 0xDB) {
1718 return {
1719 ext: 'rpm',
1720 mime: 'application/x-rpm',
1721 };
1722 }
1723
1724 if (
1725 (buf[0] === 0x1F && buf[1] === 0xA0) ||
1726 (buf[0] === 0x1F && buf[1] === 0x9D)
1727 ) {
1728 return {
1729 ext: 'Z',
1730 mime: 'application/x-compress',
1731 };
1732 }
1733
1734 if (buf[0] === 0x4C && buf[1] === 0x5A && buf[2] === 0x49 && buf[3] === 0x50) {
1735 return {
1736 ext: 'lz',
1737 mime: 'application/x-lzip',
1738 };
1739 }
1740
1741 if (
1742 buf[0] === 0xD0 && buf[1] === 0xCF && buf[2] === 0x11 && buf[3] === 0xE0 && buf[4] === 0xA1 && buf[5] === 0xB1 &&
1743 buf[6] === 0x1A && buf[7] === 0xE1
1744 ) {
1745 return {
1746 ext: 'msi',
1747 mime: 'application/x-msi',
1748 };
1749 }
1750
1751 if (
1752 buf[0] === 0x06 && buf[1] === 0x0E && buf[2] === 0x2B && buf[3] === 0x34 && buf[4] === 0x02 && buf[5] === 0x05 &&
1753 buf[6] === 0x01 && buf[7] === 0x01 && buf[8] === 0x0D && buf[9] === 0x01 && buf[10] === 0x02 && buf[11] === 0x01 &&
1754 buf[12] === 0x01 && buf[13] === 0x02
1755 ) {
1756 return {
1757 ext: 'mxf',
1758 mime: 'application/mxf',
1759 };
1760 }
1761
1762 return null;
1763 }
1764 })();
1765
1766 function lookupMime(ext) {
1767 return mimes[ext.replace(/^\./, '')] || mimes.bin;
1768 }
1769
1770 function lookupBuffer(buffer) {
1771 const ret = mimeOfBuffer(buffer);
1772 return ret ? ret.mime : mimes.bin;
1773 }
1774
1775 mime = {
1776 buffer: lookupBuffer,
1777 lookup: lookupMime,
1778 };
1779 })();
1780
1781 FormData = class {
1782 constructor() {
1783 this.boundary = `--snekfetch--${Math.random().toString().slice(2, 7)}`;
1784 this.buffers = [];
1785 }
1786
1787 append(name, data, filename) {
1788 if (typeof data === 'undefined') {
1789 return;
1790 }
1791 let str = `\r\n--${this.boundary}\r\nContent-Disposition: form-data; name="${name}"`;
1792 let mimetype = null;
1793 if (filename) {
1794 str += `; filename="${filename}"`;
1795 mimetype = 'application/octet-stream';
1796 const extname = path.extname(filename)
1797 .slice(1);
1798 if (extname) {
1799 mimetype = mime.lookup(extname);
1800 }
1801 }
1802
1803 if (data instanceof Buffer) {
1804 mimetype = mime.buffer(data);
1805 } else if (typeof data === 'object') {
1806 mimetype = 'application/json';
1807 data = Buffer.from(JSON.stringify(data));
1808 } else {
1809 data = Buffer.from(String(data));
1810 }
1811
1812 if (mimetype) {
1813 str += `\r\nContent-Type: ${mimetype}`;
1814 }
1815 this.buffers.push(Buffer.from(`${str}\r\n\r\n`));
1816 this.buffers.push(data);
1817 }
1818
1819 getBoundary() {
1820 return this.boundary;
1821 }
1822
1823 end() {
1824 return Buffer.concat([...this.buffers, Buffer.from(`\r\n--${this.boundary}--`)]);
1825 }
1826
1827 get length() {
1828 return this.buffers.reduce((sum, b) => sum + Buffer.byteLength(b), 0);
1829 }
1830 }
1831 })();
1832
1833 function shouldUnzip(statusCode, headers) {
1834 /* istanbul ignore next */
1835 if (statusCode === 204 || statusCode === 304) {
1836 return false;
1837 }
1838 if (+headers['content-length'] === 0) {
1839 return false;
1840 }
1841 return /^\s*(?:deflate|gzip)\s*$/.test(headers['content-encoding']);
1842 }
1843
1844 function request(snek, options = snek.options) {
1845 return new Promise(async (resolve, reject) => {
1846 Object.assign(options, UrlParse(options.url));
1847
1848 let {
1849 data
1850 } = options;
1851 if (data && data.end) {
1852 data = data.end();
1853 }
1854
1855 if (!options.headers['content-length']) {
1856 let length = 0;
1857 if (data) {
1858 try {
1859 length = Buffer.byteLength(data);
1860 } catch (err) {} // eslint-disable-line no-empty
1861 }
1862 options.headers['content-length'] = length;
1863 }
1864
1865 let req;
1866 let http2 = false;
1867 try {
1868 if (options.connection && options.connection.port === options.port &&
1869 options.connection.host === options.host) {
1870 req = socket.http2req(options.connection, options);
1871 http2 = true;
1872 } else {
1873 const O = await socket(options);
1874 ({
1875 req
1876 } = O);
1877 if (O.http2) {
1878 http2 = true;
1879 }
1880 if (O.connection) {
1881 options.connection = O.connection;
1882 }
1883 }
1884 } catch (err) {
1885 reject(err);
1886 return;
1887 }
1888
1889 req.once('error', reject);
1890
1891 const body = [];
1892 let headers;
1893 let statusCode;
1894 let statusText;
1895
1896 const handleResponse = (stream) => {
1897 if (options.redirect === 'follow' && [301, 302, 303, 307, 308].includes(statusCode)) {
1898 resolve(request(snek, Object.assign({}, options, {
1899 url: UrlResolve(options.url, headers.location),
1900 })));
1901 if (req.abort) {
1902 req.abort();
1903 } else if (req.close) {
1904 req.close();
1905 }
1906 return;
1907 }
1908
1909 stream.once('error', reject);
1910
1911 if (shouldUnzip(statusCode, headers)) {
1912 stream = stream.pipe(zlib.createUnzip({
1913 flush: zlib.Z_SYNC_FLUSH,
1914 finishFlush: zlib.Z_SYNC_FLUSH,
1915 }));
1916
1917 stream.once('error', reject);
1918 }
1919
1920 stream.on('data', (chunk) => {
1921 /* istanbul ignore next */
1922 if (!snek.push(chunk)) {
1923 snek.pause();
1924 }
1925 body.push(chunk);
1926 });
1927
1928 stream.once('end', () => {
1929 snek.push(null);
1930 const raw = Buffer.concat(body);
1931 if (options.connection && options.connection.close) {
1932 options.connection.close();
1933 }
1934 resolve({
1935 raw,
1936 headers,
1937 statusCode,
1938 statusText,
1939 });
1940 });
1941 };
1942
1943 req.on('response', (res) => {
1944 if (!http2) {
1945 statusText = res.statusMessage || STATUS_CODES[statusCode];
1946 ({
1947 headers,
1948 statusCode
1949 } = res);
1950 handleResponse(res);
1951 } else {
1952 statusCode = res[':status'];
1953 statusText = STATUS_CODES[statusCode];
1954 headers = res;
1955 handleResponse(req);
1956 }
1957 });
1958
1959 /* istanbul ignore next */
1960 if (data instanceof Stream) {
1961 data.pipe(req);
1962 } else if (data instanceof Buffer) {
1963 req.write(data);
1964 } else if (data) {
1965 req.write(data);
1966 }
1967 req.end();
1968 });
1969 }
1970
1971 transport = {
1972 request,
1973 shouldSendRaw: (data) => data instanceof Buffer || data instanceof Stream,
1974 querystring,
1975 METHODS,
1976 FormData,
1977 Parent: Stream.Readable,
1978 };
1979 })();
1980
1981 /**
1982 * Snekfetch
1983 * @extends Stream.Readable
1984 * @extends Promise
1985 */
1986 class Snekfetch extends transport.Parent {
1987 /**
1988 * Options to pass to the Snekfetch constructor
1989 * @typedef {object} SnekfetchOptions
1990 * @memberof Snekfetch
1991 * @property {object} [headers] Headers to initialize the request with
1992 * @property {object|string|Buffer} [data] Data to initialize the request with
1993 * @property {string|Object} [query] Query to intialize the request with
1994 * @property {boolean} [redirect='follow'] If the request should follow redirects
1995 * @property {object} [qs=querystring] Querystring module to use, any object providing
1996 * `stringify` and `parse` for querystrings
1997 * @property {external:Agent|boolean} [agent] Whether to use an http agent
1998 */
1999
2000 /**
2001 * Create a request.
2002 * Usually you'll want to do `Snekfetch#method(url [, options])` instead of
2003 * `new Snekfetch(method, url [, options])`
2004 * @param {string} method HTTP method
2005 * @param {string} url URL
2006 * @param {SnekfetchOptions} [opts] Options
2007 */
2008 constructor(method, url, opts = {}) {
2009 super();
2010 this.options = Object.assign({
2011 qs: transport.querystring,
2012 method,
2013 url,
2014 redirect: 'follow',
2015 }, opts, {
2016 headers: {},
2017 query: undefined,
2018 data: undefined,
2019 });
2020 if (opts.headers) {
2021 this.set(opts.headers);
2022 }
2023 if (opts.query) {
2024 this.query(opts.query);
2025 }
2026 if (opts.data) {
2027 this.send(opts.data);
2028 }
2029 }
2030
2031 /**
2032 * Add a query param to the request
2033 * @param {string|Object} name Name of query param or object to add to query
2034 * @param {string} [value] If name is a string value, this will be the value of the query param
2035 * @returns {Snekfetch} This request
2036 */
2037 query(name, value) {
2038 if (this.options.query === undefined) {
2039 this.options.query = {};
2040 }
2041 if (typeof name === 'object') {
2042 Object.assign(this.options.query, name);
2043 } else {
2044 this.options.query[name] = value;
2045 }
2046
2047 return this;
2048 }
2049
2050 /**
2051 * Add a header to the request
2052 * @param {string|Object} name Name of query param or object to add to headers
2053 * @param {string} [value] If name is a string value, this will be the value of the header
2054 * @returns {Snekfetch} This request
2055 */
2056 set(name, value) {
2057 if (typeof name === 'object') {
2058 for (const [k, v] of Object.entries(name)) {
2059 this.options.headers[k.toLowerCase()] = v;
2060 }
2061 } else {
2062 this.options.headers[name.toLowerCase()] = value;
2063 }
2064
2065 return this;
2066 }
2067
2068 /**
2069 * Attach a form data object
2070 * @param {string} name Name of the form attachment
2071 * @param {string|Object|Buffer} data Data for the attachment
2072 * @param {string} [filename] Optional filename if form attachment name needs to be overridden
2073 * @returns {Snekfetch} This request
2074 */
2075 attach(...args) {
2076 const form = this.options.data instanceof transport.FormData ?
2077 this.options.data : this.options.data = new transport.FormData();
2078 if (typeof args[0] === 'object') {
2079 for (const [k, v] of Object.entries(args[0])) {
2080 this.attach(k, v);
2081 }
2082 } else {
2083 form.append(...args);
2084 }
2085
2086 return this;
2087 }
2088
2089 /**
2090 * Send data with the request
2091 * @param {string|Buffer|Object} data Data to send
2092 * @returns {Snekfetch} This request
2093 */
2094 send(data) {
2095 if (data instanceof transport.FormData || transport.shouldSendRaw(data)) {
2096 this.options.data = data;
2097 } else if (data !== null && typeof data === 'object') {
2098 const header = this.options.headers['content-type'];
2099 let serialize;
2100 if (header) {
2101 if (header.includes('application/json')) {
2102 serialize = JSON.stringify;
2103 } else if (header.includes('urlencoded')) {
2104 serialize = this.options.qs.stringify;
2105 }
2106 } else {
2107 this.set('Content-Type', 'application/json');
2108 serialize = JSON.stringify;
2109 }
2110 this.options.data = serialize(data);
2111 } else {
2112 this.options.data = data;
2113 }
2114 return this;
2115 }
2116
2117 then(resolver, rejector) {
2118 if (this._response) {
2119 return this._response.then(resolver, rejector);
2120 }
2121 this._finalizeRequest();
2122 // eslint-disable-next-line no-return-assign
2123 return this._response = transport.request(this)
2124 .then(({
2125 raw,
2126 headers,
2127 statusCode,
2128 statusText
2129 }) => {
2130 // forgive me :(
2131 const self = this; // eslint-disable-line consistent-this
2132 /**
2133 * Response from Snekfetch
2134 * @typedef {Object} SnekfetchResponse
2135 * @memberof Snekfetch
2136 * @prop {HTTP.Request} request
2137 * @prop {?string|object|Buffer} body Processed response body
2138 * @prop {Buffer} raw Raw response body
2139 * @prop {boolean} ok If the response code is >= 200 and < 300
2140 * @prop {number} statusCode HTTP status code
2141 * @prop {string} statusText Human readable HTTP status
2142 */
2143 const res = {
2144 request: this.request,
2145 get body() {
2146 delete res.body;
2147 const type = res.headers['content-type'];
2148 if (raw instanceof ArrayBuffer) {
2149 raw = new window.TextDecoder('utf8')
2150 .decode(raw); // eslint-disable-line no-undef
2151 }
2152 if (/application\/json/.test(type)) {
2153 try {
2154 res.body = JSON.parse(raw);
2155 } catch (err) {
2156 res.body = String(raw);
2157 }
2158 } else if (/application\/x-www-form-urlencoded/.test(type)) {
2159 res.body = self.options.qs.parse(String(raw));
2160 } else {
2161 res.body = raw;
2162 }
2163 return res.body;
2164 },
2165 raw,
2166 ok: statusCode >= 200 && statusCode < 400,
2167 headers,
2168 statusCode,
2169 statusText,
2170 };
2171
2172 if (res.ok) {
2173 return res;
2174 }
2175 const err = new Error(`${statusCode} ${statusText}`.trim());
2176 Object.assign(err, res);
2177 return Promise.reject(err);
2178 })
2179 .then(resolver, rejector);
2180 }
2181
2182 catch (rejector) {
2183 return this.then(null, rejector);
2184 }
2185
2186 /**
2187 * End the request
2188 * @param {Function} [cb] Optional callback to handle the response
2189 * @returns {Promise} This request
2190 */
2191 end(cb) {
2192 return this.then(
2193 (res) => (cb ? cb(null, res) : res),
2194 (err) => (cb ? cb(err, err.statusCode ? err : null) : Promise.reject(err))
2195 );
2196 }
2197
2198 _finalizeRequest() {
2199 if (this.options.method !== 'HEAD') {
2200 this.set('Accept-Encoding', 'gzip, deflate');
2201 }
2202 if (this.options.data && this.options.data.getBoundary) {
2203 this.set('Content-Type', `multipart/form-data; boundary=${this.options.data.getBoundary()}`);
2204 }
2205
2206 if (this.options.query) {
2207 const [url, query] = this.options.url.split('?');
2208 this.options.url = `${url}?${this.options.qs.stringify(this.options.query)}${query ? `&${query}` : ''}`;
2209 }
2210 }
2211
2212 _read() {
2213 this.resume();
2214 if (this._response) {
2215 return;
2216 }
2217 this.catch((err) => this.emit('error', err));
2218 }
2219 }
2220
2221 /**
2222 * Create a ((THIS)) request
2223 * @dynamic this.METHODS
2224 * @method Snekfetch.((THIS)lowerCase)
2225 * @param {string} url The url to request
2226 * @param {Snekfetch.snekfetchOptions} [opts] Options
2227 * @returns {Snekfetch}
2228 */
2229 Snekfetch.METHODS = transport.METHODS.filter((m) => m !== 'M-SEARCH');
2230 for (const method of Snekfetch.METHODS) {
2231 Snekfetch[method.toLowerCase()] = function runMethod(url, opts) {
2232 const Constructor = this && this.prototype instanceof Snekfetch ? this : Snekfetch;
2233 return new Constructor(method, url, opts);
2234 };
2235 }
2236
2237 snekfetch = Snekfetch;
2238 })();
2239
2240 // discordjs Snowflake
2241 let Snowflake;
2242 (() => {
2243 /*
2244 Apache License
2245 Version 2.0, January 2004
2246 http://www.apache.org/licenses/
2247
2248 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
2249
2250 1. Definitions.
2251
2252 "License" shall mean the terms and conditions for use, reproduction,
2253 and distribution as defined by Sections 1 through 9 of this document.
2254
2255 "Licensor" shall mean the copyright owner or entity authorized by
2256 the copyright owner that is granting the License.
2257
2258 "Legal Entity" shall mean the union of the acting entity and all
2259 other entities that control, are controlled by, or are under common
2260 control with that entity. For the purposes of this definition,
2261 "control" means (i) the power, direct or indirect, to cause the
2262 direction or management of such entity, whether by contract or
2263 otherwise, or (ii) ownership of fifty percent (50%) or more of the
2264 outstanding shares, or (iii) beneficial ownership of such entity.
2265
2266 "You" (or "Your") shall mean an individual or Legal Entity
2267 exercising permissions granted by this License.
2268
2269 "Source" form shall mean the preferred form for making modifications,
2270 including but not limited to software source code, documentation
2271 source, and configuration files.
2272
2273 "Object" form shall mean any form resulting from mechanical
2274 transformation or translation of a Source form, including but
2275 not limited to compiled object code, generated documentation,
2276 and conversions to other media types.
2277
2278 "Work" shall mean the work of authorship, whether in Source or
2279 Object form, made available under the License, as indicated by a
2280 copyright notice that is included in or attached to the work
2281 (an example is provided in the Appendix below).
2282
2283 "Derivative Works" shall mean any work, whether in Source or Object
2284 form, that is based on (or derived from) the Work and for which the
2285 editorial revisions, annotations, elaborations, or other modifications
2286 represent, as a whole, an original work of authorship. For the purposes
2287 of this License, Derivative Works shall not include works that remain
2288 separable from, or merely link (or bind by name) to the interfaces of,
2289 the Work and Derivative Works thereof.
2290
2291 "Contribution" shall mean any work of authorship, including
2292 the original version of the Work and any modifications or additions
2293 to that Work or Derivative Works thereof, that is intentionally
2294 submitted to Licensor for inclusion in the Work by the copyright owner
2295 or by an individual or Legal Entity authorized to submit on behalf of
2296 the copyright owner. For the purposes of this definition, "submitted"
2297 means any form of electronic, verbal, or written communication sent
2298 to the Licensor or its representatives, including but not limited to
2299 communication on electronic mailing lists, source code control systems,
2300 and issue tracking systems that are managed by, or on behalf of, the
2301 Licensor for the purpose of discussing and improving the Work, but
2302 excluding communication that is conspicuously marked or otherwise
2303 designated in writing by the copyright owner as "Not a Contribution."
2304
2305 "Contributor" shall mean Licensor and any individual or Legal Entity
2306 on behalf of whom a Contribution has been received by Licensor and
2307 subsequently incorporated within the Work.
2308
2309 2. Grant of Copyright License. Subject to the terms and conditions of
2310 this License, each Contributor hereby grants to You a perpetual,
2311 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
2312 copyright license to reproduce, prepare Derivative Works of,
2313 publicly display, publicly perform, sublicense, and distribute the
2314 Work and such Derivative Works in Source or Object form.
2315
2316 3. Grant of Patent License. Subject to the terms and conditions of
2317 this License, each Contributor hereby grants to You a perpetual,
2318 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
2319 (except as stated in this section) patent license to make, have made,
2320 use, offer to sell, sell, import, and otherwise transfer the Work,
2321 where such license applies only to those patent claims licensable
2322 by such Contributor that are necessarily infringed by their
2323 Contribution(s) alone or by combination of their Contribution(s)
2324 with the Work to which such Contribution(s) was submitted. If You
2325 institute patent litigation against any entity (including a
2326 cross-claim or counterclaim in a lawsuit) alleging that the Work
2327 or a Contribution incorporated within the Work constitutes direct
2328 or contributory patent infringement, then any patent licenses
2329 granted to You under this License for that Work shall terminate
2330 as of the date such litigation is filed.
2331
2332 4. Redistribution. You may reproduce and distribute copies of the
2333 Work or Derivative Works thereof in any medium, with or without
2334 modifications, and in Source or Object form, provided that You
2335 meet the following conditions:
2336
2337 (a) You must give any other recipients of the Work or
2338 Derivative Works a copy of this License; and
2339
2340 (b) You must cause any modified files to carry prominent notices
2341 stating that You changed the files; and
2342
2343 (c) You must retain, in the Source form of any Derivative Works
2344 that You distribute, all copyright, patent, trademark, and
2345 attribution notices from the Source form of the Work,
2346 excluding those notices that do not pertain to any part of
2347 the Derivative Works; and
2348
2349 (d) If the Work includes a "NOTICE" text file as part of its
2350 distribution, then any Derivative Works that You distribute must
2351 include a readable copy of the attribution notices contained
2352 within such NOTICE file, excluding those notices that do not
2353 pertain to any part of the Derivative Works, in at least one
2354 of the following places: within a NOTICE text file distributed
2355 as part of the Derivative Works; within the Source form or
2356 documentation, if provided along with the Derivative Works; or,
2357 within a display generated by the Derivative Works, if and
2358 wherever such third-party notices normally appear. The contents
2359 of the NOTICE file are for informational purposes only and
2360 do not modify the License. You may add Your own attribution
2361 notices within Derivative Works that You distribute, alongside
2362 or as an addendum to the NOTICE text from the Work, provided
2363 that such additional attribution notices cannot be construed
2364 as modifying the License.
2365
2366 You may add Your own copyright statement to Your modifications and
2367 may provide additional or different license terms and conditions
2368 for use, reproduction, or distribution of Your modifications, or
2369 for any such Derivative Works as a whole, provided Your use,
2370 reproduction, and distribution of the Work otherwise complies with
2371 the conditions stated in this License.
2372
2373 5. Submission of Contributions. Unless You explicitly state otherwise,
2374 any Contribution intentionally submitted for inclusion in the Work
2375 by You to the Licensor shall be under the terms and conditions of
2376 this License, without any additional terms or conditions.
2377 Notwithstanding the above, nothing herein shall supersede or modify
2378 the terms of any separate license agreement you may have executed
2379 with Licensor regarding such Contributions.
2380
2381 6. Trademarks. This License does not grant permission to use the trade
2382 names, trademarks, service marks, or product names of the Licensor,
2383 except as required for reasonable and customary use in describing the
2384 origin of the Work and reproducing the content of the NOTICE file.
2385
2386 7. Disclaimer of Warranty. Unless required by applicable law or
2387 agreed to in writing, Licensor provides the Work (and each
2388 Contributor provides its Contributions) on an "AS IS" BASIS,
2389 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
2390 implied, including, without limitation, any warranties or conditions
2391 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
2392 PARTICULAR PURPOSE. You are solely responsible for determining the
2393 appropriateness of using or redistributing the Work and assume any
2394 risks associated with Your exercise of permissions under this License.
2395
2396 8. Limitation of Liability. In no event and under no legal theory,
2397 whether in tort (including negligence), contract, or otherwise,
2398 unless required by applicable law (such as deliberate and grossly
2399 negligent acts) or agreed to in writing, shall any Contributor be
2400 liable to You for damages, including any direct, indirect, special,
2401 incidental, or consequential damages of any character arising as a
2402 result of this License or out of the use or inability to use the
2403 Work (including but not limited to damages for loss of goodwill,
2404 work stoppage, computer failure or malfunction, or any and all
2405 other commercial damages or losses), even if such Contributor
2406 has been advised of the possibility of such damages.
2407
2408 9. Accepting Warranty or Additional Liability. While redistributing
2409 the Work or Derivative Works thereof, You may choose to offer,
2410 and charge a fee for, acceptance of support, warranty, indemnity,
2411 or other liability obligations and/or rights consistent with this
2412 License. However, in accepting such obligations, You may act only
2413 on Your own behalf and on Your sole responsibility, not on behalf
2414 of any other Contributor, and only if You agree to indemnify,
2415 defend, and hold each Contributor harmless for any liability
2416 incurred by, or claims asserted against, such Contributor by reason
2417 of your accepting any such warranty or additional liability.
2418
2419 END OF TERMS AND CONDITIONS
2420
2421 Copyright 2015 - 2018 Amish Shah
2422
2423 Licensed under the Apache License, Version 2.0 (the "License");
2424 you may not use this file except in compliance with the License.
2425 You may obtain a copy of the License at
2426
2427 http://www.apache.org/licenses/LICENSE-2.0
2428
2429 Unless required by applicable law or agreed to in writing, software
2430 distributed under the License is distributed on an "AS IS" BASIS,
2431 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2432 See the License for the specific language governing permissions and
2433 limitations under the License.
2434 */
2435 // Modified by including only the stuff needed for discord-rpc
2436 // discordjs Util
2437 const Util = {
2438 binaryToID: function binaryToID(num) {
2439 let dec = '';
2440
2441 while (num.length > 50) {
2442 const high = parseInt(num.slice(0, -32), 2);
2443 const low = parseInt((high % 10)
2444 .toString(2) + num.slice(-32), 2);
2445
2446 dec = (low % 10)
2447 .toString() + dec;
2448 num = Math.floor(high / 10)
2449 .toString(2) + Math.floor(low / 10)
2450 .toString(2)
2451 .padStart(32, '0');
2452 }
2453
2454 num = parseInt(num, 2);
2455 while (num > 0) {
2456 dec = (num % 10)
2457 .toString() + dec;
2458 num = Math.floor(num / 10);
2459 }
2460
2461 return dec;
2462 },
2463 idToBinary: function idToBinary(num) {
2464 let bin = '';
2465 let high = parseInt(num.slice(0, -10)) || 0;
2466 let low = parseInt(num.slice(-10));
2467 while (low > 0 || high > 0) {
2468 bin = String(low & 1) + bin;
2469 low = Math.floor(low / 2);
2470 if (high > 0) {
2471 low += 5000000000 * (high % 2);
2472 high = Math.floor(high / 2);
2473 }
2474 }
2475 return bin;
2476 }
2477 };
2478
2479 // Discord epoch (2015-01-01T00:00:00.000Z)
2480 const EPOCH = 1420070400000;
2481 let INCREMENT = 0;
2482
2483 /**
2484 * A container for useful snowflake-related methods.
2485 */
2486 class SnowflakeUtil {
2487 constructor() {
2488 throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
2489 }
2490
2491 /**
2492 * A Twitter snowflake, except the epoch is 2015-01-01T00:00:00.000Z
2493 * ```
2494 * If we have a snowflake '266241948824764416' we can represent it as binary:
2495 *
2496 * 64 22 17 12 0
2497 * 000000111011000111100001101001000101000000 00001 00000 000000000000
2498 * number of ms since Discord epoch worker pid increment
2499 * ```
2500 * @typedef {string} Snowflake
2501 */
2502
2503 /**
2504 * Generates a Discord snowflake.
2505 * <info>This hardcodes the worker ID as 1 and the process ID as 0.</info>
2506 * @param {number|Date} [timestamp=Date.now()] Timestamp or date of the snowflake to generate
2507 * @returns {Snowflake} The generated snowflake
2508 */
2509 static generate(timestamp = Date.now()) {
2510 if (timestamp instanceof Date) timestamp = timestamp.getTime();
2511 if (typeof timestamp !== 'number' || isNaN(timestamp)) {
2512 throw new TypeError(
2513 `"timestamp" argument must be a number (received ${isNaN(timestamp) ? 'NaN' : typeof timestamp})`
2514 );
2515 }
2516 if (INCREMENT >= 4095) INCREMENT = 0;
2517 // eslint-disable-next-line max-len
2518 const BINARY = `${(timestamp - EPOCH).toString(2).padStart(42, '0')}0000100000${(INCREMENT++).toString(2).padStart(12, '0')}`;
2519 return Util.binaryToID(BINARY);
2520 }
2521
2522 /**
2523 * A deconstructed snowflake.
2524 * @typedef {Object} DeconstructedSnowflake
2525 * @property {number} timestamp Timestamp the snowflake was created
2526 * @property {Date} date Date the snowflake was created
2527 * @property {number} workerID Worker ID in the snowflake
2528 * @property {number} processID Process ID in the snowflake
2529 * @property {number} increment Increment in the snowflake
2530 * @property {string} binary Binary representation of the snowflake
2531 */
2532
2533 /**
2534 * Deconstructs a Discord snowflake.
2535 * @param {Snowflake} snowflake Snowflake to deconstruct
2536 * @returns {DeconstructedSnowflake} Deconstructed snowflake
2537 */
2538 static deconstruct(snowflake) {
2539 const BINARY = Util.idToBinary(snowflake)
2540 .toString(2)
2541 .padStart(64, '0');
2542 const res = {
2543 timestamp: parseInt(BINARY.substring(0, 42), 2) + EPOCH,
2544 workerID: parseInt(BINARY.substring(42, 47), 2),
2545 processID: parseInt(BINARY.substring(47, 52), 2),
2546 increment: parseInt(BINARY.substring(52, 64), 2),
2547 binary: BINARY,
2548 };
2549 Object.defineProperty(res, 'date', {
2550 get: function get() {
2551 return new Date(this.timestamp);
2552 },
2553 enumerable: true,
2554 });
2555 return res;
2556 }
2557 }
2558
2559 Snowflake = SnowflakeUtil;
2560 })();
2561
2562 // discordjs/RPC library
2563 let RPCClient;
2564 (() => {
2565 // https://github.com/discordjs/RPC
2566 const {
2567 setTimeout,
2568 clearTimeout
2569 } = require('timers');
2570 const request = snekfetch;
2571 let transports;
2572 (() => {
2573 const net = require('net');
2574 const EventEmitter = require('events');
2575 const request = snekfetch;
2576
2577 const OPCodes = {
2578 HANDSHAKE: 0,
2579 FRAME: 1,
2580 CLOSE: 2,
2581 PING: 3,
2582 PONG: 4,
2583 };
2584
2585 class IPCTransport extends EventEmitter {
2586 constructor(client) {
2587 super();
2588 this.client = client;
2589 this.socket = null;
2590 }
2591
2592 async connect({
2593 client_id
2594 }) {
2595 const socket = this.socket = await getIPC();
2596 this.emit('open');
2597 socket.write(encode(OPCodes.HANDSHAKE, {
2598 v: 1,
2599 client_id,
2600 }));
2601 socket.pause();
2602 socket.on('readable', () => {
2603 decode(socket, ({
2604 op,
2605 data
2606 }) => {
2607 switch (op) {
2608 case OPCodes.PING:
2609 this.send(data, OPCodes.PONG);
2610 break;
2611 case OPCodes.FRAME:
2612 if (!data) {
2613 return;
2614 }
2615 if (data.cmd === 'AUTHORIZE' && data.evt !== 'ERROR') {
2616 findEndpoint()
2617 .then((endpoint) => {
2618 this.client.rest.endpoint = endpoint;
2619 this.client.rest.versioned = false;
2620 });
2621 }
2622 this.emit('message', data);
2623 break;
2624 case OPCodes.CLOSE:
2625 this.emit('close', data);
2626 break;
2627 default:
2628 break;
2629 }
2630 });
2631 });
2632 socket.on('close', this.onClose.bind(this));
2633 socket.on('error', this.onClose.bind(this));
2634 }
2635
2636 onClose(e) {
2637 this.emit('close', e);
2638 }
2639
2640 send(data, op = OPCodes.FRAME) {
2641 this.socket.write(encode(op, data));
2642 }
2643
2644 close() {
2645 this.send({}, OPCodes.CLOSE);
2646 this.socket.end();
2647 }
2648
2649 ping() {
2650 this.send(Snowflake.generate(), OPCodes.PING);
2651 }
2652 }
2653
2654 function encode(op, data) {
2655 data = JSON.stringify(data);
2656 const len = Buffer.byteLength(data);
2657 const packet = Buffer.alloc(8 + len);
2658 packet.writeInt32LE(op, 0);
2659 packet.writeInt32LE(len, 4);
2660 packet.write(data, 8, len);
2661 return packet;
2662 }
2663
2664 const working = {
2665 full: '',
2666 op: undefined,
2667 };
2668
2669 function decode(socket, callback) {
2670 const packet = socket.read();
2671 if (!packet) {
2672 return;
2673 }
2674
2675 let op = working.op;
2676 let raw;
2677 if (working.full === '') {
2678 op = working.op = packet.readInt32LE(0);
2679 const len = packet.readInt32LE(4);
2680 raw = packet.slice(8, len + 8);
2681 } else {
2682 raw = packet.toString();
2683 }
2684
2685 try {
2686 const data = JSON.parse(working.full + raw);
2687 callback({
2688 op,
2689 data
2690 }); // eslint-disable-line callback-return
2691 working.full = '';
2692 working.op = undefined;
2693 } catch (err) {
2694 working.full += raw;
2695 }
2696
2697 decode(socket, callback);
2698 }
2699
2700 function getIPCPath(id) {
2701 if (process.platform === 'win32') {
2702 return `\\\\?\\pipe\\discord-ipc-${id}`;
2703 }
2704 const {
2705 env: {
2706 XDG_RUNTIME_DIR,
2707 TMPDIR,
2708 TMP,
2709 TEMP
2710 }
2711 } = process;
2712 const prefix = XDG_RUNTIME_DIR || TMPDIR || TMP || TEMP || '/tmp';
2713 return `${prefix.replace(/\/$/, '')}/discord-ipc-${id}`;
2714 }
2715
2716 function getIPC(id = 0) {
2717 return new Promise((resolve, reject) => {
2718 const path = getIPCPath(id);
2719 const onerror = () => {
2720 if (id < 10) {
2721 resolve(getIPC(id + 1));
2722 } else {
2723 reject(new Error('Could not connect'));
2724 }
2725 };
2726 const sock = net.createConnection(path, () => {
2727 sock.removeListener('error', onerror);
2728 resolve(sock);
2729 });
2730 sock.once('error', onerror);
2731 });
2732 }
2733
2734 function findEndpoint(tries = 0) {
2735 if (tries > 30) {
2736 throw new Error('Could not find endpoint');
2737 }
2738 const endpoint = `http://127.0.0.1:${6463 + (tries % 10)}`;
2739 return request.get(endpoint)
2740 .end((err, res) => {
2741 if ((err.status || res.status) === 401) {
2742 return endpoint;
2743 }
2744 return findEndpoint(tries + 1);
2745 });
2746 }
2747
2748 transports = {};
2749 transports.ipc = IPCTransport;
2750 transports.ipc.encode = encode;
2751 transports.ipc.decode = decode;
2752 })();
2753
2754 function getPid() {
2755 if (typeof process !== undefined) {
2756 return process.pid;
2757 }
2758 return null;
2759 }
2760 /**
2761 * Represents a data model that is identifiable by a Snowflake (i.e. Discord API data models).
2762 */
2763 class Base {
2764 constructor(client) {
2765 /**
2766 * The client that instantiated this
2767 * @name Base#client
2768 * @type {Client}
2769 * @readonly
2770 */
2771 Object.defineProperty(this, 'client', {
2772 value: client
2773 });
2774 }
2775
2776 _clone() {
2777 return Object.assign(Object.create(this), this);
2778 }
2779
2780 _patch(data) {
2781 return data;
2782 }
2783
2784 _update(data) {
2785 const clone = this._clone();
2786 this._patch(data);
2787 return clone;
2788 }
2789
2790 toJSON(...props) {
2791 return flatten(this, ...props);
2792 }
2793
2794 valueOf() {
2795 return this.id;
2796 }
2797 }
2798 let ClientApplication;
2799 (() => {
2800 const ClientApplicationAssetTypes = {
2801 SMALL: 1,
2802 BIG: 2,
2803 };
2804
2805 function makeImageUrl(root, {
2806 format = 'webp',
2807 size
2808 } = {}) {
2809 if (format && !AllowedImageFormats.includes(format)) throw new Error('IMAGE_FORMAT', format);
2810 if (size && !AllowedImageSizes.includes(size)) throw new RangeError('IMAGE_SIZE', size);
2811 return `${root}.${format}${size ? `?size=${size}` : ''}`;
2812 }
2813 const Endpoints = {
2814 CDN(root) {
2815 return {
2816 Emoji: (emojiID, format = 'png') => `${root}/emojis/${emojiID}.${format}`,
2817 Asset: name => `${root}/assets/${name}`,
2818 DefaultAvatar: number => `${root}/embed/avatars/${number}.png`,
2819 Avatar: (userID, hash, format = 'default', size) => {
2820 if (userID === '1') return hash;
2821 if (format === 'default') format = hash.startsWith('a_') ? 'gif' : 'webp';
2822 return makeImageUrl(`${root}/avatars/${userID}/${hash}`, {
2823 format,
2824 size
2825 });
2826 },
2827 Icon: (guildID, hash, format = 'webp', size) =>
2828 makeImageUrl(`${root}/icons/${guildID}/${hash}`, {
2829 format,
2830 size
2831 }),
2832 AppIcon: (clientID, hash, {
2833 format = 'webp',
2834 size
2835 } = {}) =>
2836 makeImageUrl(`${root}/app-icons/${clientID}/${hash}`, {
2837 size,
2838 format
2839 }),
2840 AppAsset: (clientID, hash, {
2841 format = 'webp',
2842 size
2843 } = {}) =>
2844 makeImageUrl(`${root}/app-assets/${clientID}/${hash}`, {
2845 size,
2846 format
2847 }),
2848 GDMIcon: (channelID, hash, format = 'webp', size) =>
2849 makeImageUrl(`${root}/channel-icons/${channelID}/${hash}`, {
2850 size,
2851 format
2852 }),
2853 Splash: (guildID, hash, format = 'webp', size) =>
2854 makeImageUrl(`${root}/splashes/${guildID}/${hash}`, {
2855 size,
2856 format
2857 }),
2858 };
2859 },
2860 invite: (root, code) => `${root}/${code}`,
2861 botGateway: '/gateway/bot'
2862 };
2863 const DataResolver = {
2864 resolveImage: async function(image) {
2865 if (!image) return null;
2866 if (typeof image === 'string' && image.startsWith('data:')) {
2867 return image;
2868 }
2869 const file = await DataResolver.resolveFile(image);
2870 return DataResolver.resolveBase64(file);
2871 },
2872 resolveFile: function(resource) {
2873 if (resource instanceof Buffer) return Promise.resolve(resource);
2874 if (browser && resource instanceof ArrayBuffer) return Promise.resolve(Buffer.from(resource));
2875
2876 if (typeof resource === 'string') {
2877 if (/^https?:\/\//.test(resource)) {
2878 return snekfetch.get(resource)
2879 .then(res => res.body instanceof Buffer ? res.body : Buffer.from(res.text));
2880 } else {
2881 return new Promise((resolve, reject) => {
2882 const file = browser ? resource : path.resolve(resource);
2883 fs.stat(file, (err, stats) => {
2884 if (err) return reject(err);
2885 if (!stats || !stats.isFile()) return reject(new DiscordError('FILE_NOT_FOUND', file));
2886 fs.readFile(file, (err2, data) => {
2887 if (err2) reject(err2);
2888 else resolve(data);
2889 });
2890 return null;
2891 });
2892 });
2893 }
2894 } else if (resource.pipe && typeof resource.pipe === 'function') {
2895 return new Promise((resolve, reject) => {
2896 const buffers = [];
2897 resource.once('error', reject);
2898 resource.on('data', data => buffers.push(data));
2899 resource.once('end', () => resolve(Buffer.concat(buffers)));
2900 });
2901 }
2902 return Promise.reject(new TypeError('REQ_RESOURCE_TYPE'));
2903 },
2904 resolveBase64: function(data) {
2905 if (data instanceof Buffer) return `data:image/jpg;base64,${data.toString('base64')}`;
2906 return data;
2907 }
2908 };
2909
2910 function flatten(obj, ...props) {
2911 const isObject = d => typeof d === 'object' && d !== null;
2912 if (!isObject(obj)) return obj;
2913
2914 props = Object.assign(...Object.keys(obj)
2915 .filter(k => !k.startsWith('_'))
2916 .map(k => ({
2917 [k]: true
2918 })), ...props);
2919
2920 const out = {};
2921
2922 for (let [prop, newProp] of Object.entries(props)) {
2923 if (!newProp) continue;
2924 newProp = newProp === true ? prop : newProp;
2925
2926 const element = obj[prop];
2927 const elemIsObj = isObject(element);
2928 const valueOf = elemIsObj && typeof element.valueOf === 'function' ? element.valueOf() : null;
2929
2930 // If it's an array, flatten each element
2931 if (Array.isArray(element)) out[newProp] = element.map(e => flatten(e));
2932 // If it's an object with a primitive `valueOf`, use that value
2933 else if (valueOf && !isObject(valueOf)) out[newProp] = valueOf;
2934 // If it's a primitive
2935 else if (!elemIsObj) out[newProp] = element;
2936 }
2937
2938 return out;
2939 }
2940
2941 /**
2942 * Represents a Client OAuth2 Application.
2943 * @extends {Base}
2944 */
2945 ClientApplication = class extends Base {
2946 constructor(client, data) {
2947 super(client);
2948 this._patch(data);
2949 }
2950
2951 _patch(data) {
2952 /**
2953 * The ID of the app
2954 * @type {Snowflake}
2955 */
2956 this.id = data.id;
2957
2958 /**
2959 * The name of the app
2960 * @type {string}
2961 */
2962 this.name = data.name;
2963
2964 /**
2965 * The app's description
2966 * @type {string}
2967 */
2968 this.description = data.description;
2969
2970 /**
2971 * The app's icon hash
2972 * @type {string}
2973 */
2974 this.icon = data.icon;
2975
2976 /**
2977 * The app's cover image hash
2978 * @type {?string}
2979 */
2980 this.cover = data.cover_image;
2981
2982 /**
2983 * The app's RPC origins
2984 * @type {?string[]}
2985 */
2986 this.rpcOrigins = data.rpc_origins;
2987
2988 /**
2989 * The app's redirect URIs
2990 * @type {string[]}
2991 */
2992 this.redirectURIs = data.redirect_uris;
2993
2994 /**
2995 * If this app's bot requires a code grant when using the OAuth2 flow
2996 * @type {boolean}
2997 */
2998 this.botRequireCodeGrant = data.bot_require_code_grant;
2999
3000 /**
3001 * If this app's bot is public
3002 * @type {boolean}
3003 */
3004 this.botPublic = data.bot_public;
3005
3006 /**
3007 * If this app can use rpc
3008 * @type {boolean}
3009 */
3010 this.rpcApplicationState = data.rpc_application_state;
3011
3012 /**
3013 * Object containing basic info about this app's bot
3014 * @type {Object}
3015 */
3016 this.bot = data.bot;
3017
3018 /**
3019 * The flags for the app
3020 * @type {number}
3021 */
3022 this.flags = data.flags;
3023
3024 /**
3025 * OAuth2 secret for the application
3026 * @type {string}
3027 */
3028 this.secret = data.secret;
3029
3030 if (data.owner) {
3031 /**
3032 * The owner of this OAuth application
3033 * @type {?User}
3034 */
3035 this.owner = this.client.users.add(data.owner);
3036 }
3037 }
3038
3039 /**
3040 * The timestamp the app was created at
3041 * @type {number}
3042 * @readonly
3043 */
3044 get createdTimestamp() {
3045 return Snowflake.deconstruct(this.id)
3046 .timestamp;
3047 }
3048
3049 /**
3050 * The time the app was created at
3051 * @type {Date}
3052 * @readonly
3053 */
3054 get createdAt() {
3055 return new Date(this.createdTimestamp);
3056 }
3057
3058 /**
3059 * A link to the application's icon.
3060 * @param {Object} [options={}] Options for the icon url
3061 * @param {string} [options.format='webp'] One of `webp`, `png`, `jpg`
3062 * @param {number} [options.size=128] One of `128`, `256`, `512`, `1024`, `2048`
3063 * @returns {?string} URL to the icon
3064 */
3065 iconURL({
3066 format,
3067 size
3068 } = {}) {
3069 if (!this.icon) return null;
3070 return this.client.rest.cdn.AppIcon(this.id, this.icon, {
3071 format,
3072 size
3073 });
3074 }
3075
3076 /**
3077 * A link to this application's cover image.
3078 * @param {Object} [options={}] Options for the cover image url
3079 * @param {string} [options.format='webp'] One of `webp`, `png`, `jpg`
3080 * @param {number} [options.size=128] One of `128`, `256`, `512`, `1024`, `2048`
3081 * @returns {?string} URL to the cover image
3082 */
3083 coverImage({
3084 format,
3085 size
3086 } = {}) {
3087 if (!this.cover) return null;
3088 return Endpoints
3089 .CDN(this.client.options.http.cdn)
3090 .AppIcon(this.id, this.cover, {
3091 format,
3092 size
3093 });
3094 }
3095
3096 /**
3097 * Get rich presence assets.
3098 * @returns {Promise<Object>}
3099 */
3100 fetchAssets() {
3101 const types = Object.keys(ClientApplicationAssetTypes);
3102 return this.client.api.oauth2.applications(this.id)
3103 .assets.get()
3104 .then(assets => assets.map(a => ({
3105 id: a.id,
3106 name: a.name,
3107 type: types[a.type - 1],
3108 })));
3109 }
3110
3111 /**
3112 * Creates a rich presence asset.
3113 * @param {string} name Name of the asset
3114 * @param {Base64Resolvable} data Data of the asset
3115 * @param {string} type Type of the asset. `big`, or `small`
3116 * @returns {Promise}
3117 */
3118 async createAsset(name, data, type) {
3119 return this.client.api.oauth2.applications(this.id)
3120 .assets.post({
3121 data: {
3122 name,
3123 type: ClientApplicationAssetTypes[type.toUpperCase()],
3124 image: await DataResolver.resolveImage(data),
3125 }
3126 });
3127 }
3128
3129 /**
3130 * Resets the app's secret.
3131 * <warn>This is only available when using a user account.</warn>
3132 * @returns {Promise<ClientApplication>}
3133 */
3134 resetSecret() {
3135 return this.client.api.oauth2.applications[this.id].reset.post()
3136 .then(app => new ClientApplication(this.client, app));
3137 }
3138
3139 /**
3140 * Resets the app's bot token.
3141 * <warn>This is only available when using a user account.</warn>
3142 * @returns {Promise<ClientApplication>}
3143 */
3144 resetToken() {
3145 return this.client.api.oauth2.applications[this.id].bot.reset.post()
3146 .then(app => new ClientApplication(this.client, Object.assign({}, this, {
3147 bot: app
3148 })));
3149 }
3150
3151 /**
3152 * When concatenated with a string, this automatically returns the application's name instead of the
3153 * ClientApplication object.
3154 * @returns {string}
3155 * @example
3156 * // Logs: Application name: My App
3157 * console.log(`Application name: ${application}`);
3158 */
3159 toString() {
3160 return this.name;
3161 }
3162
3163 toJSON() {
3164 return super.toJSON({
3165 createdTimestamp: true
3166 });
3167 }
3168 };
3169 })();
3170 /**
3171 * The base class for all clients.
3172 * @extends {EventEmitter}
3173 */
3174 class BaseClient extends EventEmitter {
3175 constructor(options = {}) {
3176 super();
3177
3178 /**
3179 * Timeouts set by {@link BaseClient#setTimeout} that are still active
3180 * @type {Set<Timeout>}
3181 * @private
3182 */
3183 this._timeouts = new Set();
3184
3185 /**
3186 * Intervals set by {@link BaseClient#setInterval} that are still active
3187 * @type {Set<Timeout>}
3188 * @private
3189 */
3190 this._intervals = new Set();
3191
3192 /**
3193 * The options the client was instantiated with
3194 * @type {ClientOptions}
3195 */
3196 this.options = {}; // Util.mergeDefault(DefaultOptions, options);
3197
3198 /**
3199 * The REST manager of the client
3200 * @type {RESTManager}
3201 * @private
3202 */
3203 //this.rest = new RESTManager(this, options._tokenType);
3204 }
3205
3206 /**
3207 * API shortcut
3208 * @type {Object}
3209 * @readonly
3210 * @private
3211 */
3212 get api() {
3213 return this.rest.api;
3214 }
3215
3216 /**
3217 * Destroys all assets used by the base client.
3218 */
3219 destroy() {
3220 for (const t of this._timeouts) clearTimeout(t);
3221 for (const i of this._intervals) clearInterval(i);
3222 this._timeouts.clear();
3223 this._intervals.clear();
3224 }
3225
3226 /**
3227 * Sets a timeout that will be automatically cancelled if the client is destroyed.
3228 * @param {Function} fn Function to execute
3229 * @param {number} delay Time to wait before executing (in milliseconds)
3230 * @param {...*} args Arguments for the function
3231 * @returns {Timeout}
3232 */
3233 setTimeout(fn, delay, ...args) {
3234 const timeout = setTimeout(() => {
3235 fn(...args);
3236 this._timeouts.delete(timeout);
3237 }, delay);
3238 this._timeouts.add(timeout);
3239 return timeout;
3240 }
3241
3242 /**
3243 * Clears a timeout.
3244 * @param {Timeout} timeout Timeout to cancel
3245 */
3246 clearTimeout(timeout) {
3247 clearTimeout(timeout);
3248 this._timeouts.delete(timeout);
3249 }
3250
3251 /**
3252 * Sets an interval that will be automatically cancelled if the client is destroyed.
3253 * @param {Function} fn Function to execute
3254 * @param {number} delay Time to wait between executions (in milliseconds)
3255 * @param {...*} args Arguments for the function
3256 * @returns {Timeout}
3257 */
3258 setInterval(fn, delay, ...args) {
3259 const interval = setInterval(fn, delay, ...args);
3260 this._intervals.add(interval);
3261 return interval;
3262 }
3263
3264 /**
3265 * Clears an interval.
3266 * @param {Timeout} interval Interval to cancel
3267 */
3268 clearInterval(interval) {
3269 clearInterval(interval);
3270 this._intervals.delete(interval);
3271 }
3272
3273 toJSON(...props) {
3274 return flatten(this, {
3275 domain: false
3276 }, ...props);
3277 }
3278 }
3279
3280 function createCache(create) {
3281 return {
3282 has: () => false,
3283 delete: () => false,
3284 get: () => undefined,
3285 create,
3286 };
3287 }
3288
3289 function subKey(event, args) {
3290 return `${event}${JSON.stringify(args)}`;
3291 }
3292
3293 /**
3294 * @typedef {RPCClientOptions}
3295 * @extends {ClientOptions}
3296 * @prop {string} transport RPC transport. one of `ipc` or `websocket`
3297 */
3298
3299 /**
3300 * The main hub for interacting with Discord RPC
3301 * @extends {BaseClient}
3302 */
3303 RPCClient = class extends BaseClient {
3304 /**
3305 * @param {RPCClientOptions} [options] Options for the client
3306 * You must provide a transport
3307 */
3308 constructor(options = {}) {
3309 super(Object.assign({
3310 _tokenType: 'Bearer'
3311 }, options));
3312 this.accessToken = null;
3313 this.clientID = null;
3314
3315 /**
3316 * Application used in this client
3317 * @type {?ClientApplication}
3318 */
3319 this.application = null;
3320
3321 const Transport = transports[options.transport];
3322 if (!Transport) {
3323 throw new TypeError('RPC_INVALID_TRANSPORT', options.transport);
3324 }
3325
3326
3327 /**
3328 * Raw transport userd
3329 * @type {RPCTransport}
3330 */
3331 this.transport = new Transport(this);
3332 this.transport.on('message', this._onRpcMessage.bind(this));
3333
3334 /**
3335 * Map of nonces being expected from the transport
3336 * @type {Map}
3337 * @private
3338 */
3339 this._expecting = new Map();
3340
3341 /**
3342 * Map of current subscriptions
3343 * @type {Map}
3344 * @private
3345 */
3346 this._subscriptions = new Map();
3347 }
3348
3349 /**
3350 * @typedef {RPCLoginOptions}
3351 * @param {string} [clientSecret] Client secret
3352 * @param {string} [accessToken] Access token
3353 * @param {string} [rpcToken] RPC token
3354 * @param {string} [tokenEndpoint] Token endpoint
3355 * @param {string[]} [scopes] Scopes to authorize with
3356 */
3357
3358 /**
3359 * Log in
3360 * @param {string} clientID Client ID
3361 * @param {RPCLoginOptions} options Options for authentication.
3362 * At least one property must be provided to perform login.
3363 * @example client.login('1234567', { clientSecret: 'abcdef123' });
3364 * @returns {Promise<RPCClient>}
3365 */
3366 login(clientID, options) {
3367 return new Promise((resolve, reject) => {
3368 this.clientID = clientID;
3369 this.options._login = options || {};
3370 const timeout = setTimeout(() => reject(new Error('RPC_CONNECTION_TIMEOUT')), 10e3);
3371 timeout.unref();
3372 this.once('connected', () => {
3373 clearTimeout(timeout);
3374 resolve(this);
3375 });
3376 this.transport.once('close', reject);
3377 this.transport.connect({
3378 client_id: this.clientID
3379 });
3380 })
3381 .then(() => {
3382 if (!options) {
3383 this.emit('ready');
3384 return this;
3385 }
3386 if (options.accessToken) {
3387 return this.authenticate(options.accessToken);
3388 }
3389 return this.authorize(options);
3390 });
3391 }
3392
3393 /**
3394 * Request
3395 * @param {string} cmd Command
3396 * @param {Object} [args={}] Arguments
3397 * @param {string} [evt] Event
3398 * @returns {Promise}
3399 * @private
3400 */
3401 request(cmd, args, evt) {
3402 return new Promise((resolve, reject) => {
3403 const nonce = Snowflake.generate();
3404 this.transport.send({
3405 cmd,
3406 args,
3407 evt,
3408 nonce
3409 });
3410 this._expecting.set(nonce, {
3411 resolve,
3412 reject
3413 });
3414 });
3415 }
3416
3417 /**
3418 * Message handler
3419 * @param {Object} message message
3420 * @private
3421 */
3422 _onRpcMessage(message) {
3423 if (message.cmd === "DISPATCH" && message.evt === "READY") {
3424 this.emit('connected');
3425 } else if (this._expecting.has(message.nonce)) {
3426 const {
3427 resolve,
3428 reject
3429 } = this._expecting.get(message.nonce);
3430 if (message.evt === 'ERROR') {
3431 reject(new Error('RPC_CLIENT_ERROR', `${message.data.code} ${message.data.message}`));
3432 } else {
3433 resolve(message.data);
3434 }
3435 this._expecting.delete(message.nonce);
3436 } else {
3437 const subid = subKey(message.evt, message.args);
3438 if (!this._subscriptions.has(subid)) {
3439 return;
3440 }
3441 this._subscriptions.get(subid)(message.data);
3442 }
3443 }
3444
3445 /**
3446 * Authorize
3447 * @param {Object} options options
3448 * @returns {Promise}
3449 * @private
3450 */
3451 async authorize({
3452 rpcToken,
3453 scopes,
3454 clientSecret,
3455 tokenEndpoint
3456 }) {
3457 if (tokenEndpoint && !rpcToken) {
3458 rpcToken = await request.get(tokenEndpoint)
3459 .then((r) => r.body.rpc_token);
3460 } else if (clientSecret && rpcToken === true) {
3461 rpcToken = await this.api.oauth2.token.rpc.post({
3462 headers: {
3463 'Content-Type': 'application/x-www-form-urlencoded'
3464 },
3465 data: {
3466 client_id: this.clientID,
3467 client_secret: clientSecret,
3468 },
3469 });
3470 }
3471
3472 const {
3473 code
3474 } = await this.request('AUTHORIZE', {
3475 client_id: this.clientID,
3476 scopes,
3477 rpc_token: rpcToken,
3478 });
3479
3480 if (tokenEndpoint) {
3481 const r = await request.post(tokenEndpoint)
3482 .send({
3483 code
3484 });
3485 return this.authenticate(r.body.access_token);
3486 } else if (clientSecret) {
3487 const {
3488 access_token: accessToken
3489 } = await this.api.oauth2.token.post({
3490 query: {
3491 client_id: this.clientID,
3492 client_secret: clientSecret,
3493 code,
3494 grant_type: 'authorization_code',
3495 },
3496 auth: false,
3497 });
3498 return this.authenticate(accessToken);
3499 }
3500
3501 return {
3502 code
3503 };
3504 }
3505
3506 /**
3507 * Authenticate
3508 * @param {string} accessToken access token
3509 * @returns {Promise}
3510 * @private
3511 */
3512 authenticate(accessToken) {
3513 this.accessToken = accessToken;
3514 return this.request('AUTHENTICATE', {
3515 access_token: accessToken
3516 })
3517 .then(({
3518 application,
3519 user
3520 }) => {
3521 this.application = new ClientApplication(this, application);
3522 this.emit('ready');
3523 return this;
3524 });
3525 }
3526
3527 setActivity(args = {}, pid = getPid()) {
3528 let timestamps;
3529 let assets;
3530 let party;
3531 let secrets;
3532 if (args.startTimestamp || args.endTimestamp) {
3533 timestamps = {
3534 start: args.startTimestamp,
3535 end: args.endTimestamp,
3536 };
3537 if (timestamps.start instanceof Date) {
3538 timestamps.start = parseInt(timestamps.start.getTime());
3539 } else if (typeof timestamps.start === 'number') {
3540 timestamps.start = parseInt(timestamps.start)
3541 }
3542 if (timestamps.end instanceof Date) {
3543 timestamps.end = parseInt(timestamps.end.getTime());
3544 } else if (typeof timestamps.end === 'number') {
3545 timestamps.end = parseInt(timestamps.end.getTime());
3546 }
3547 }
3548 if (
3549 args.largeImageKey || args.largeImageText ||
3550 args.smallImageKey || args.smallImageText
3551 ) {
3552 assets = {
3553 large_image: args.largeImageKey,
3554 large_text: args.largeImageText,
3555 small_image: args.smallImageKey,
3556 small_text: args.smallImageText,
3557 };
3558 }
3559 if (args.partySize || args.partyId || args.partyMax) {
3560 party = {
3561 id: args.partyId
3562 };
3563 if (args.partySize || args.partyMax) {
3564 party.size = [args.partySize, args.partyMax];
3565 }
3566 }
3567 if (args.matchSecret || args.joinSecret || args.spectateSecret) {
3568 secrets = {
3569 match: args.matchSecret,
3570 join: args.joinSecret,
3571 spectate: args.spectateSecret,
3572 };
3573 }
3574
3575 return this.request("SET_ACTIVITY", {
3576 pid,
3577 activity: {
3578 state: args.state,
3579 details: args.details,
3580 timestamps,
3581 assets,
3582 party,
3583 secrets,
3584 instance: !!args.instance,
3585 },
3586 });
3587 }
3588
3589 /**
3590 * Clears the currently set presence, if any. This will hide the "Playing X" message
3591 * displayed below the user's name.
3592 * @param {number} [pid] The application's process ID. Defaults to the executing process' PID.
3593 * @returns {Promise}
3594 */
3595 clearActivity(pid = getPid()) {
3596 return this.request("SET_ACTIVITY", {
3597 pid,
3598 });
3599 }
3600
3601 /**
3602 * Subscribe to an event
3603 * @param {string} event Name of event e.g. `MESSAGE_CREATE`
3604 * @param {Object} [args] Args for event e.g. `{ channel_id: '1234' }`
3605 * @param {Function} callback Callback when an event for the subscription is triggered
3606 * @returns {Promise<Object>}
3607 */
3608 subscribe(event, args, callback) {
3609 if (!callback && typeof args === 'function') {
3610 callback = args;
3611 args = undefined;
3612 }
3613 return this.request("SUBSCRIBE", args, event)
3614 .then(() => {
3615 const subid = subKey(event, args);
3616 this._subscriptions.set(subid, callback);
3617 return {
3618 unsubscribe: () => this.request("UNSUBSCRIBE", args, event)
3619 .then(() => this._subscriptions.delete(subid)),
3620 };
3621 });
3622 }
3623
3624 /**
3625 * Destroy the client
3626 */
3627 async destroy() {
3628 super.destroy();
3629 this.transport.close();
3630 }
3631 }
3632 })();
3633
3634 // https://github.com/devsnek/discord-rich-presence
3635 function makeClient(id) {
3636 const rpc = new RPCClient({
3637 transport: 'ipc'
3638 });
3639
3640 let connected = false;
3641 let activityCache = null;
3642
3643 const instance = new class RP extends EventEmitter {
3644 updatePresence(d) {
3645 if (connected)
3646 rpc.setActivity(d)
3647 .catch((e) => this.emit('error', e));
3648 else
3649 activityCache = d;
3650 }
3651
3652 reply(user, response) {
3653 const handle = (e) => this.emit('error', e);
3654 switch (response) {
3655 case 'YES':
3656 rpc.sendJoinInvite(user)
3657 .catch(handle);
3658 break;
3659 case 'NO':
3660 case 'IGNORE':
3661 rpc.closeJoinRequest(user)
3662 .catch(handle);
3663 }
3664 }
3665
3666 disconnect() {
3667 rpc.destroy()
3668 .catch((e) => this.emit('error', e));
3669 }
3670 };
3671
3672 rpc.login(id)
3673 .then(() => {
3674 instance.emit('connected');
3675 connected = true;
3676 if (activityCache) {
3677 rpc.setActivity(activityCache)
3678 .catch((e) => instance.emit("setActivityFailed", e));
3679 activityCache = null;
3680 }
3681 })
3682 .catch((e) => instance.emit("loginFailed", e));
3683
3684 return instance;
3685 }
3686
3687 RPClient = makeClient;
3688})();
3689
3690class AutoStartRichPresence {
3691 getName() {
3692 return "AutoStartRichPresence";
3693 }
3694 getShortName() {
3695 return "AutoStartRichPresence";
3696 }
3697 getDescription() {
3698 return "Auto starts Rich Presence with configurable settings.\nRequired dependency: ZeresPluginLibrary\n\nMy Discord server: https://nebula.mooo.info/discord-invite\nDM me @Lucario ☉ ∠x²#7902 or create an issue at https://github.com/Mega-Mewthree/BetterDiscordPlugins for support.";
3699 }
3700 getVersion() {
3701 return "1.1.0";
3702 }
3703 getAuthor() {
3704 return "Mega_Mewthree"; //Current Discord account: @Lucario ☉ ∠x²#7902 (438469378418409483)
3705 }
3706 constructor() {
3707 this.initialized = false;
3708 this.client = null;
3709 }
3710 load() {}
3711 unload() {}
3712 start() {
3713 if (typeof window.ZeresPluginLibrary === "undefined") {
3714 BdApi.showToast('AutoStartRichPresence: Please install "ZeresPluginLibrary" and restart this plugin.', {type: "error"});
3715 } else {
3716 this.initialize();
3717 }
3718 }
3719 initialize() {
3720 if (window.ZeresPluginLibrary.PluginUtilities && typeof window.ZeresPluginLibrary.PluginUtilities.checkForUpdate === "function") {
3721 try {
3722 window.ZeresPluginLibrary.PluginUtilities.checkForUpdate(this.getName(), this.getVersion(), `https://raw.githubusercontent.com/Mega-Mewthree/BetterDiscordPlugins/master/Plugins/${this.getName()}/${this.getName()}.plugin.js`);
3723 } catch (e) {
3724 console.error(e);
3725 }
3726 }
3727 BdApi.showToast("AutoStartRichPresence has started!");
3728 this.startTime = Date.now();
3729 this.settings = BdApi.loadData("AutoStartRichPresence", "settings") || {};
3730 this.currentClientID = this.settings.clientID;
3731 this.rpcClientInfo = {};
3732 this.discordSetActivityHandler = null;
3733 this.startRichPresence();
3734 this.initialized = true;
3735 }
3736 async stop() {
3737 if (this.settings.experimentalRPCEventInjection) await this.experimental_stopRichPresence();
3738 await this.stopRichPresence();
3739 this.initialized = false;
3740 BdApi.showToast("AutoStartRichPresence has stopped!");
3741 }
3742 getSettingsPanel() {
3743 if (!this.initialized) return;
3744 this.settings = BdApi.loadData("AutoStartRichPresence", "settings") || {};
3745 const panel = $("<form>").addClass("form").css("width", "100%");
3746 if (this.initialized) this.generateSettings(panel);
3747 return panel[0];
3748 }
3749 async startRichPresence() {
3750 if (this.settings.experimentalRPCEventInjection) return await this.experimental_startRichPresence();
3751 this.currentTimeout && clearTimeout(this.currentTimeout);
3752 this.currentTimeout = setTimeout(async () => {
3753 this.client && typeof this.client.removeAllListeners === "function" && this.client.removeAllListeners() && typeof this.client.disconnect === "function" && await this.client.disconnect();
3754 this.client = RPClient(this.currentClientID);
3755 this.client.on("setActivityFailed", e => {
3756 console.error(e);
3757 BdApi.showToast("Failed to set Rich Presence activity.", {type: "error"});
3758 });
3759 this.client.on("loginFailed", async e => {
3760 console.error(e);
3761 this.client && typeof this.client.removeAllListeners === "function" && this.client.removeAllListeners() && typeof this.client.disconnect === "function" && await this.client.disconnect();
3762 BdApi.showToast("Rich Presence client ID authentication failed. Make sure your client ID is correct.", {type: "error"});
3763 });
3764 this.client.updatePresence({
3765 details: this.settings.details || undefined,
3766 state: this.settings.state || undefined,
3767 startTimestamp: this.settings.enableStartTime ? this.startTime / 1000 : undefined,
3768 largeImageKey: this.settings.largeImageKey || undefined,
3769 smallImageKey: this.settings.smallImageKey || undefined,
3770 largeImageText: this.settings.largeImageText || undefined,
3771 smallImageText: this.settings.smallImageText || undefined
3772 });
3773 }, 5000);
3774 }
3775 updateRichPresence() {
3776 if (this.settings.experimentalRPCEventInjection) return this.experimental_updateRichPresence();
3777 this.currentTimeout && clearTimeout(this.currentTimeout);
3778 this.currentTimeout = setTimeout(() => {
3779 if (!this.client || this.currentClientID !== this.settings.clientID) {
3780 this.currentClientID = this.settings.clientID;
3781 return this.startRichPresence();
3782 }
3783 this.client.updatePresence({
3784 details: this.settings.details || undefined,
3785 state: this.settings.state || undefined,
3786 startTimestamp: this.settings.enableStartTime ? this.startTime / 1000 : undefined,
3787 largeImageKey: this.settings.largeImageKey || undefined,
3788 smallImageKey: this.settings.smallImageKey || undefined,
3789 largeImageText: this.settings.largeImageText || undefined,
3790 smallImageText: this.settings.smallImageText || undefined
3791 });
3792 }, 5000);
3793 }
3794 async stopRichPresence() {
3795 this.client && typeof this.client.disconnect === "function" && await this.client.disconnect();
3796 }
3797 async experimental_startRichPresence() {
3798 const RPCValidatorModule = BdApi.findModuleByProps("validateSocketClient");
3799 const validateRPC = RPCValidatorModule.validateSocketClient.bind(RPCValidatorModule);
3800 let validationObject = {
3801 application: {id: null, name: null, icon: null},
3802 authorization: {accessToken: null, authing: false, expires: new Date(0), scopes: []},
3803 encoding: "json",
3804 transport: "ipc",
3805 id: "1",
3806 version: 1
3807 };
3808 try {
3809 await validateRPC(validationObject, null, this.currentClientID);
3810 } catch (e) {
3811 if (e.message === "Invalid Client ID") {
3812 return BdApi.showToast("Rich Presence client ID authentication failed. Make sure your client ID is correct.", {type: "error"});
3813 }
3814 }
3815 this.rpcClientInfo = validationObject.application;
3816 return await this.experimental_updateRichPresence();
3817 }
3818 async experimental_updateRichPresence() {
3819 if (this.currentClientID !== this.settings.clientID) {
3820 this.currentClientID = this.settings.clientID;
3821 return await this.experimental_startRichPresence();
3822 }
3823 const SetActivityModule = BdApi.findModuleByProps("SET_ACTIVITY").SET_ACTIVITY;
3824 if (!this.discordSetActivityHandler) this.discordSetActivityHandler = SetActivityModule.handler;
3825 SetActivityModule.handler = function () {};
3826 const setActivity = this.discordSetActivityHandler.bind(SetActivityModule);
3827 setActivity(this.buildActivityObject());
3828 }
3829 async experimental_stopRichPresence() {
3830 if (this.discordSetActivityHandler) {
3831 const SetActivityModule = BdApi.findModuleByProps("SET_ACTIVITY").SET_ACTIVITY;
3832 SetActivityModule.handler = this.discordSetActivityHandler;
3833 // I don't know how to unset the Rich Presence yet.
3834 return BdApi.showToast("Restart Discord to clear your current presence.", {type: "info"});
3835 }
3836 }
3837 buildActivityObject() {
3838 const activityObject = {
3839 socket: {
3840 transport: "ipc",
3841 id: "1",
3842 version: 1,
3843 encoding: "json",
3844 application: {
3845 id: this.currentClientID,
3846 name: this.rpcClientInfo.name,
3847 icon: null,
3848 coverImage: this.rpcClientInfo.coverImage,
3849 flags: this.rpcClientInfo.flags
3850 }
3851 },
3852 cmd: "SET_ACTIVITY",
3853 args: {
3854 pid: require("process").pid,
3855 activity: {
3856 timestamps: {},
3857 assets: {},
3858 name: this.rpcClientInfo.name,
3859 application_id: this.currentClientID
3860 }
3861 }
3862 };
3863 if (this.settings.details) {
3864 activityObject.args.activity.details = this.settings.details;
3865 }
3866 if (this.settings.state) {
3867 activityObject.args.activity.state = this.settings.state;
3868 }
3869 if (this.settings.enableStartTime) {
3870 activityObject.args.activity.timestamps.start = Math.floor(this.startTime / 1000) * 1000;
3871 }
3872 if (this.settings.largeImageKey) {
3873 activityObject.args.activity.assets.large_image = this.settings.largeImageKey;
3874 if (this.settings.largeImageText) {
3875 activityObject.args.activity.assets.large_text = this.settings.largeImageText;
3876 }
3877 }
3878 if (this.settings.smallImageKey) {
3879 activityObject.args.activity.assets.small_image = this.settings.smallImageKey;
3880 if (this.settings.smallImageText) {
3881 activityObject.args.activity.assets.small_text = this.settings.smallImageText;
3882 }
3883 }
3884 return activityObject;
3885 }
3886 updateSettings() {
3887 BdApi.saveData("AutoStartRichPresence", "settings", this.settings);
3888 }
3889 generateSettings(panel) {
3890 new window.ZeresPluginLibrary.Settings.SettingGroup("Rich Presence Configuration", {collapsible: false, shown: true, callback: () => {this.updateSettings(); this.updateRichPresence();}}).appendTo(panel).append(
3891 new window.ZeresPluginLibrary.Settings.Textbox("Client ID", "The client ID of your Discord Rich Presence application.", this.settings.clientID || "", val => {this.settings.clientID = val;}),
3892 new window.ZeresPluginLibrary.Settings.Textbox("Details", "The line that goes after your game's name.", this.settings.details || "", val => {this.settings.details = val;}),
3893 new window.ZeresPluginLibrary.Settings.Textbox("State", "The line that goes after the details.", this.settings.state || "", val => {this.settings.state = val;}),
3894 new window.ZeresPluginLibrary.Settings.Textbox("Large Image Key", "The name of the asset for your large image.", this.settings.largeImageKey || "", val => {this.settings.largeImageKey = val;}),
3895 new window.ZeresPluginLibrary.Settings.Textbox("Large Image Text", "The text that appears when your large image is hovered over.", this.settings.largeImageText || "", val => {this.settings.largeImageText = val;}),
3896 new window.ZeresPluginLibrary.Settings.Textbox("Small Image Key", "The name of the asset for your small image.", this.settings.smallImageKey || "", val => {this.settings.smallImageKey = val;}),
3897 new window.ZeresPluginLibrary.Settings.Textbox("Small Image Text", "The text that appears when your small image is hovered over.", this.settings.smallImageText || "", val => {this.settings.smallImageText = val;}),
3898 new window.ZeresPluginLibrary.Settings.Switch("Enable Start Time", "Displays the amount of time your Rich Presence is enabled.", this.settings.enableStartTime, val => {this.settings.enableStartTime = val;}),
3899 new window.ZeresPluginLibrary.Settings.Switch("Experimental: RPC Event Injection", "Bypasses the use of IPC and hopefully prevents other programs from using their own Rich Presences.", this.settings.experimentalRPCEventInjection, async val => {this.settings.experimentalRPCEventInjection = val; if (val) {await this.stopRichPresence(); await this.experimental_startRichPresence();} else {await this.experimental_stopRichPresence(); await this.startRichPresence();}})
3900 );
3901 let div = document.createElement("div");
3902 div.innerHTML = '<a href="https://discordapp.com/developers/applications/me" rel="noreferrer noopener" target="_blank">Create or edit your Discord Rich Presence application here!</a>';
3903 panel[0].appendChild(div);
3904 div = document.createElement("div");
3905 div.innerHTML = '<a href="https://www.youtube.com/watch?v=JIUOreTNj-o" rel="noreferrer noopener" target="_blank">Click here for a video tutorial of how to set up this plugin!</a>';
3906 panel[0].appendChild(div);
3907 }
3908}
3909/*
3910-----BEGIN PGP SIGNATURE-----
3911
3912iQEzBAEBCgAdFiEEGTGecftnrhRz9oomf4qgY6FcSQsFAlyy3s4ACgkQf4qgY6Fc
3913SQuXLQf/a93/99pRdMKERCrpohhb5+VhN7GOhO2EgQaT75/TtzETjNHDk9bq9/uu
3914WJDm7hKbDN2eZHomdjNpA97FXkwpoHSNC81TehPqMH0yExx4UjtGkyZwNQzAA1Au
3915re9F8pTuyCsUFpVg69edc08kJdXyrgiwf09q+0ZWXCH0+SniJ0+WOhIOIRTXqW73
3916VeS1xdUAKY/0jG+Gjh81rJgQXgZvign2rUepeZ4YEpNSzbv4/v4CaO+4BoD1d74D
3917qK8O2AOkq+elIE9wLDN4PzUmMfIDRbArcWeso+I86GdPtZu8IfsXxQm0S4i530kt
3918fypb/P6y8Xz2EpkUe0vj28Blo1K7Ww==
3919=ZlYC
3920-----END PGP SIGNATURE-----
3921*/