function.js (23865B)
1 const { 2 EmbedBuilder, 3 ActionRowBuilder, 4 ButtonBuilder, 5 ButtonStyle, 6 } = require("discord.js"); 7 /** 8 * Returns a random element from an array 9 * @returns {any} 10 */ 11 Array.prototype.random = function () { 12 return this[~~(Math.random() * this.length)]; 13 }; 14 15 function rndint(max, min) { 16 return Math.floor(Math.random() * (max - (min ? min : 0))) + (min ? min : 0); 17 } 18 19 const months = [ 20 "January", 21 "February", 22 "March", 23 "April", 24 "May", 25 "June", 26 "July", 27 "August", 28 "September", 29 "October", 30 "November", 31 "December", 32 ]; 33 34 function parseDate(date) { 35 let dow = date.getDate().toString(); 36 return `${date.toLocaleDateString("en-US", { 37 weekday: "long", 38 })}, ${months[date.getMonth()]} ${ 39 dow.endsWith("1") 40 ? `${dow}st` 41 : dow.endsWith("2") 42 ? `${dow}nd` 43 : dow.endsWith("3") 44 ? `${dow}rd` 45 : `${dow}th` 46 } ${date.getFullYear()}, ${date.toLocaleTimeString()}`; 47 } 48 49 function parseShortDate(date) { 50 let dow = date.getDate().toString(); 51 return `${months[date.getMonth()]} ${ 52 dow.endsWith("1") 53 ? `${dow}st` 54 : dow.endsWith("2") 55 ? `${dow}nd` 56 : dow.endsWith("3") 57 ? `${dow}rd` 58 : `${dow}th` 59 } ${date.getFullYear()}`; 60 } 61 function timer(timestamp) { 62 const timeLeft = timestamp; 63 const days = Math.floor(timeLeft / 86400000); 64 const hours = Math.floor(timeLeft / 3600000) - days * 24; 65 const minutes = Math.floor(timeLeft / 60000) - days * 1440 - hours * 60; 66 const seconds = 67 Math.floor(timeLeft / 1000) - days * 86400 - hours * 3600 - minutes * 60; 68 const mseconds = timeLeft / 1000 - days * 86400 - hours * 3600 - minutes * 60; 69 let string = ""; 70 if (days) string = string + `${days} ${days == 1 ? "day " : "days "}`; 71 if (hours) string = string + `${hours} ${hours == 1 ? "hour " : "hours "}`; 72 if (minutes) { 73 string = string + `${minutes} ${minutes == 1 ? "minute " : "minutes "}`; 74 } 75 if (seconds) { 76 string = string + `${seconds} ${seconds == 1 ? "second " : "seconds "}`; 77 } 78 if (!string.length) string = `${mseconds.toFixed(1)} second`; 79 return string; 80 } 81 function sleep(ms) { 82 new Promise(resolve => setTimeout(resolve, ms)); 83 } 84 function toHHMMSS(str) { 85 const sec_num = parseInt(str, 10); 86 let hours = Math.floor(sec_num / 3600); 87 let minutes = Math.floor((sec_num - hours * 3600) / 60); 88 let seconds = sec_num - hours * 3600 - minutes * 60; 89 if (hours < 10) { 90 hours = "0" + hours; 91 } 92 if (minutes < 10) { 93 minutes = "0" + minutes; 94 } 95 if (seconds < 10) { 96 seconds = "0" + seconds; 97 } 98 return hours + ":" + minutes + ":" + seconds; 99 } 100 function fixPermissions(arr = Array) { 101 const permissions = { 102 ADMINISTRATOR: "Administrator", 103 VIEW_AUDIT_LOG: "View Audit Log", 104 VIEW_GUILD_INSIGHTS: "View Server Insights", 105 MANAGE_GUILD: "Manage Server", 106 MANAGE_ROLES: "Manage Roles", 107 MANAGE_CHANNELS: "Manage Channels", 108 KICK_MEMBERS: "Kick Members", 109 BAN_MEMBERS: "Ban Members", 110 CREATE_INSTANT_INVITE: "Create Invite", 111 CHANGE_NICKNAME: "Change Nickname", 112 MANAGE_NICKNAMES: "Manage Nicknames", 113 MANAGE_EMOJIS_AND_STICKERS: "Manage Emojis and Stickers", 114 MANAGE_WEBHOOKS: "Manage Webhooks", 115 VIEW_CHANNEL: "Read Text Channels & See Voice Channels", 116 SEND_MESSAGES: "Send Messages", 117 SEND_TTS_MESSAGES: "Send TTS Messages", 118 MANAGE_MESSAGES: "Manage Messages", 119 EMBED_LINKS: "Embed Links", 120 ATTACH_FILES: "Attach Files", 121 READ_MESSAGE_HISTORY: "Read Message History", 122 MENTION_EVERYONE: "Mention @everyone, @here, and All Roles", 123 USE_EXTERNAL_EMOJIS: "Use External Emojis", 124 ADD_REACTIONS: "Add Reactions", 125 CONNECT: "Connect", 126 SPEAK: "Speak", 127 STREAM: "Video", 128 MUTE_MEMBERS: "Mute Members", 129 DEAFEN_MEMBERS: "Deafen Members", 130 MOVE_MEMBERS: "Move Members", 131 USE_VAD: "Use Voice Activity", 132 PRIORITY_SPEAKER: "Priority Speaker", 133 REQUEST_TO_SPEAK: "Request to Speak", 134 MANAGE_THREADS: "Manage Threads", 135 USE_PUBLIC_THREADS: "Use Public Threads", 136 USE_PRIVATE_THREADS: "Use Private Threads", 137 USE_EXTERNAL_STICKERS: "Use External Stickers", 138 USE_APPLICATION_COMMANDS: "Use Application Commands", 139 }; 140 const final = []; 141 for (const perm in permissions) { 142 if (arr.includes(perm)) final.push(`โ๏ธ ${permissions[perm]}`); 143 else final.push(`โ ${permissions[perm]}`); 144 } 145 return `${`\`\`\`diff\n${final.join("\n")}\`\`\``}`; 146 } 147 function formatPerms(perm) { 148 return perm 149 .toLowerCase() 150 .replace(/(^|"|_)(\S)/g, s => s.toUpperCase()) 151 .replace(/_/g, " ") 152 .replace(/Guild/g, "Server") 153 .replace(/Use Vad/g, "Use Voice Acitvity"); 154 } 155 function trimArray(arr = []) { 156 if (arr.length > 10) { 157 const length = arr.length - 10; 158 arr = arr.slice(0, 10); 159 arr.push(`\n${length} more...`); 160 } 161 return arr.join(" **|** "); 162 } 163 function checkDays(date) { 164 const now = new Date(); 165 const diff = now.getTime() - date.getTime(); 166 const days = Math.floor(diff / 86400000); 167 return days + (days == 1 ? " day" : " days") + " ago"; 168 } 169 function format(str) { 170 return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); 171 } 172 function fixFeatures(arr = []) { 173 const all = { 174 ANIMATED_ICON: "Animated Icon", 175 BANNER: "Banner", 176 COMMERCE: "Commerce", 177 COMMUNITY: "Community", 178 DISCOVERABLE: "Discoverable", 179 FEATURABLE: "Featurable", 180 INVITE_SPLASH: "Invite Splash", 181 MEMBER_VERIFICATION_GATE_ENABLED: "Member Verification Gate Enabled", 182 NEWS: "News", 183 PARTNERED: "Partnered", 184 PREVIEW_ENABLED: "Preview Enabled", 185 VANITY_URL: "Vanity URL", 186 VERIFIED: "Verified", 187 VIP_REGIONS: "VIP Region", 188 WELCOME_SCREEN_ENABLED: "Welcome Screen Enabled", 189 TICKETED_EVENTS_ENABLED: "Ticketed Events Enabled", 190 MONETIZATION_ENABLED: "Monetization Enabled", 191 MORE_STICKERS: "More Stickers", 192 THREE_DAY_THREAD_ARCHIVE: "Three Day Thread Archive", 193 SEVEN_DAY_THREAD_ARCHIVE: "Seven Day Thread Archive", 194 PRIVATE_THREADS: "Private Threads,", 195 }; 196 const final = []; 197 for (const feature in all) { 198 if (arr.includes(feature)) final.push(`โ ${all[feature]}`); 199 } 200 return `${final.join("\n")}`; 201 } 202 function cooldown(dbtime, defaults, msg) { 203 const expiration_time = dbtime + defaults; 204 const time_left = expiration_time - Date.now(); 205 const slow = [ 206 "Keep it slow...", 207 "Calm down", 208 "Stop it. Get some help.", 209 "Too fast", 210 "Slow down little bit", 211 ]; 212 const slowed = slow[Math.floor(Math.random() * slow.length)]; 213 return msg.followUp({ 214 embeds: [ 215 new EmbedBuilder() 216 .setColor("Random") 217 .setTimestamp() 218 .setTitle(slowed) 219 .setDescription( 220 `Wait **${timer( 221 time_left 222 )}** to use the command again!\nThe default cooldown is **${timer( 223 defaults 224 )}**` 225 ), 226 ], 227 }); 228 } 229 const s = 1000; 230 const m = s * 60; 231 const h = m * 60; 232 const d = h * 24; 233 const mn = d * 30; 234 const w = d * 7; 235 const y = d * 365.25; 236 237 /** 238 * @param {String|Number} val 239 * @param {Object} [options] 240 * @throws {Error} throw an error if val is not a non-empty string or a number 241 * @return {String|Number} 242 */ 243 244 function ms(val, options) { 245 options = options || {}; 246 const type = typeof val; 247 if (type === "string" && val.length > 0) { 248 return parse(val); 249 } else if (type === "number" && isFinite(val)) { 250 return options.long ? fmtLong(val) : fmtShort(val); 251 } 252 throw new Error( 253 "val is not a non-empty string or a valid number. val=" + 254 JSON.stringify(val) 255 ); 256 } 257 258 /** 259 * @param {String} str 260 * @return {Number} 261 */ 262 263 function parse(str) { 264 str = String(str); 265 if (str.length > 100) { 266 return; 267 } 268 const match = 269 /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|months?|mths|mn|years?|yrs?|y)?$/i.exec( 270 str 271 ); 272 if (!match) { 273 return; 274 } 275 const n = parseFloat(match[1]); 276 const type = (match[2] || "ms").toLowerCase(); 277 switch (type) { 278 case "years": 279 case "year": 280 case "yrs": 281 case "yr": 282 case "y": 283 return n * y; 284 case "month": 285 case "months": 286 case "mth": 287 case "mths": 288 return n * mn; 289 case "weeks": 290 case "week": 291 case "w": 292 return n * w; 293 case "days": 294 case "day": 295 case "d": 296 return n * d; 297 case "hours": 298 case "hour": 299 case "hrs": 300 case "hr": 301 case "h": 302 return n * h; 303 case "minutes": 304 case "minute": 305 case "mins": 306 case "min": 307 case "m": 308 return n * m; 309 case "seconds": 310 case "second": 311 case "secs": 312 case "sec": 313 case "s": 314 return n * s; 315 case "milliseconds": 316 case "millisecond": 317 case "msecs": 318 case "msec": 319 case "ms": 320 return n; 321 default: 322 return undefined; 323 } 324 } 325 326 /** 327 * Short format for `ms`. 328 * 329 * @param {Number} ms 330 * @return {String} 331 * @api private 332 */ 333 334 function fmtShort(ms) { 335 const msAbs = Math.abs(ms); 336 if (msAbs >= mn) { 337 return Math.round(ms / mn) + "mo"; 338 } 339 if (msAbs >= w) { 340 return Math.round(ms / w) + "w"; 341 } 342 if (msAbs >= d) { 343 return Math.round(ms / d) + "d"; 344 } 345 if (msAbs >= h) { 346 return Math.round(ms / h) + "h"; 347 } 348 if (msAbs >= m) { 349 return Math.round(ms / m) + "m"; 350 } 351 if (msAbs >= s) { 352 return Math.round(ms / s) + "s"; 353 } 354 return ms + "ms"; 355 } 356 357 /** 358 * @param {Number} ms 359 * @return {String} 360 */ 361 362 function fmtLong(ms) { 363 const msAbs = Math.abs(ms); 364 if (msAbs >= mn) { 365 return plural(ms, msAbs, mn, "month"); 366 } 367 if (msAbs >= w) { 368 return plural(ms, msAbs, w, "week"); 369 } 370 if (msAbs >= d) { 371 return plural(ms, msAbs, d, "day"); 372 } 373 if (msAbs >= h) { 374 return plural(ms, msAbs, h, "hour"); 375 } 376 if (msAbs >= m) { 377 return plural(ms, msAbs, m, "minute"); 378 } 379 if (msAbs >= s) { 380 return plural(ms, msAbs, s, "second"); 381 } 382 return ms + " ms"; 383 } 384 function plural(ms, msAbs, nz, name) { 385 const isPlural = msAbs >= nz * 1.5; 386 return Math.round(ms / nz) + " " + name + (isPlural ? "s" : ""); 387 } 388 async function confirmation(message, author, validReactions, time = 60000) { 389 try { 390 for (const reaction of validReactions) await message.react(reaction); 391 const filter = (reaction, user) => 392 validReactions.includes(reaction.emoji.name) && user.id === author.id; 393 394 return message 395 .awaitReactions({ filter, max: 1, time: time }) 396 .then(collected => collected.first() && collected.first().emoji.name); 397 } catch (_) {} 398 } 399 function selectRandom(array = []) { 400 return array[Math.floor(Math.random() * array.length)]; 401 } 402 function getAllTextFromEmbed(embed) { 403 let text = ""; 404 function getTime(now) { 405 const date = new Date(now); 406 const escape = value => `0${value}`.slice(-2); 407 const ampm = date.getHours() >= 12 ? "PM" : "AM"; 408 409 return `${date.getMonth()}/${date.getDate()}/${date.getFullYear()} at ${escape( 410 date.getHours() 411 )}:${escape(date.getMinutes())}:${escape(date.getSeconds())}${ampm}`; 412 } 413 414 if (embed.title) { 415 text += `**${embed.title 416 .replace(/(https?:\/\/)?discord\.gg\/(\w+)/g, "Invite") 417 .replace(/\[(.*)\]\((.*)\)/g, "Hyper link")}**`; 418 } 419 if (embed.description) { 420 text += `\n${embed.description 421 .replace(/(https?:\/\/)?discord\.gg\/(\w+)/g, "Invite") 422 .replace(/\[(.*)\]\((.*)\)/g, "Hyper link")}`; 423 } 424 if (embed.fields) { 425 text += "\n"; 426 for (const field of embed.fields) { 427 text += `\n**${field.name 428 .replace(/(https?:\/\/)?discord\.gg\/(\w+)/g, "Invite") 429 .replace(/\[(.*)\]\((.*)\)/g, "Hyper link")}**\n ${field.value 430 .replace(/(https?:\/\/)?discord\.gg\/(\w+)/g, "Invite") 431 .replace(/\[(.*)\]\((.*)\)/g, "Hyper link")}`; 432 } 433 } 434 if (embed.footer) { 435 let field = `\n\n**${embed.footer.text 436 .replace(/(https?:\/\/)?discord\.gg\/(\w+)/g, "Invite") 437 .replace(/\[(.*)\]\((.*)\)/g, "Hyper link")}`; 438 439 if (embed.timestamp) { 440 const time = 441 embed.timestamp instanceof Date 442 ? getTime(embed.timestamp.getTime()) 443 : embed.timestamp; 444 field += `at ${time}`; 445 } 446 447 text += `${field}**`; 448 } 449 450 return text; 451 } 452 function clean(text) { 453 if (typeof text === "string") { 454 return text 455 .replace(/`/g, "`" + String.fromCharCode(8203)) 456 .replace(/@/g, "@" + String.fromCharCode(8203)); 457 } else { 458 return text; 459 } 460 } 461 function tips(interaction, client) { 462 const all = [ 463 "You can report bugs by using `/report` and send a suggestion by `/suggest` !", 464 "If a gun isn't there, please be paitent and wait for the us to get the stats", 465 "We all recruiting for Javascript bot developers (Total: 4) Please DM the bot for more info", 466 ]; 467 const ran = Math.floor(Math.random() * 50) + 2; 468 const rTip = all[Math.floor(Math.random() * all.length)]; 469 if (ran <= 11) { 470 interaction.channel.send({ 471 embeds: [ 472 new EmbedBuilder() 473 .setTitle("Tips") 474 .setColor(client.color) 475 .setDescription(`**๐ก Did you know**\n${rTip}`) 476 .setFooter({ 477 text: `Made by ${client.author}`, 478 iconURL: client.user.displayAvatarURL({ dynamic: true }), 479 }) 480 .setTimestamp() 481 .setURL(client.web), 482 ], 483 }); 484 } 485 } 486 function inviteLink(client_id) { 487 return `https://discord.com/oauth2/authorize?client_id=${client_id}&permissions=1512097384560&scope=bot%20applications.commands`; 488 } 489 function buttons(client) { 490 const invite = new ButtonBuilder() 491 .setLabel("Invite the bot!") 492 .setStyle(ButtonStyle.Link) 493 .setEmoji("896527406100283462") 494 .setURL(inviteLink(client.user.id)); 495 const support = new ButtonBuilder() 496 .setLabel("Support Server") 497 .setStyle(ButtonStyle.Link) 498 .setEmoji("867093614403256350") 499 .setURL(client.invite); 500 const website = new ButtonBuilder() 501 .setLabel("Website") 502 .setStyle(ButtonStyle.Link) 503 .setEmoji("๐ฅ") 504 .setURL(client.web); 505 const youtube = new ButtonBuilder() 506 .setLabel("YouTube") 507 .setStyle(ButtonStyle.Link) 508 .setEmoji("841186450497339412") 509 .setURL("https://www.youtube.com/@night0721"); 510 const kofi = new ButtonBuilder() 511 .setLabel("Ko-fi") 512 .setStyle(ButtonStyle.Link) 513 .setEmoji("900590344364757013") 514 .setURL("https://ko-fi.com/cathteam"); 515 const row = new ActionRowBuilder().addComponents( 516 invite, 517 support, 518 website, 519 youtube, 520 kofi 521 ); 522 return [row]; 523 } 524 const colorize = (...args) => ({ 525 black: `\x1b[30m${args.join(" ")}`, 526 red: `\x1b[31m${args.join(" ")}`, 527 green: `\x1b[32m${args.join(" ")}`, 528 yellow: `\x1b[33m${args.join(" ")}`, 529 blue: `\x1b[34m${args.join(" ")}`, 530 magenta: `\x1b[35m${args.join(" ")}`, 531 cyan: `\x1b[36m${args.join(" ")}`, 532 white: `\x1b[37m${args.join(" ")}`, 533 bgBlack: `\x1b[40m${args.join(" ")}\x1b[0m`, 534 bgRed: `\x1b[41m${args.join(" ")}\x1b[0m`, 535 bgGreen: `\x1b[42m${args.join(" ")}\x1b[0m`, 536 bgYellow: `\x1b[43m${args.join(" ")}\x1b[0m`, 537 bgBlue: `\x1b[44m${args.join(" ")}\x1b[0m`, 538 bgMagenta: `\x1b[45m${args.join(" ")}\x1b[0m`, 539 bgCyan: `\x1b[46m${args.join(" ")}\x1b[0m`, 540 bgWhite: `\x1b[47m${args.join(" ")}\x1b[0m`, 541 }); 542 const leven = (te, t) => { 543 if (!te.length) return t.length; 544 if (!t.length) return te.length; 545 const arr = []; 546 for (let i = 0; i <= t.length; i++) { 547 arr[i] = [i]; 548 for (let j = 1; j <= te.length; j++) { 549 arr[i][j] = 550 i === 0 551 ? j 552 : Math.min( 553 arr[i - 1][j] + 1, 554 arr[i][j - 1] + 1, 555 arr[i - 1][j - 1] + (te[j - 1] === t[i - 1] ? 0 : 1) 556 ); 557 } 558 } 559 return arr[t.length][te.length]; 560 }; 561 function chunk(arr, size) { 562 Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => { 563 arr.slice(i * size, i * size + size); 564 return arr; 565 }); 566 } 567 function progressBar(value, maxValue, size) { 568 const percentage = value / maxValue; 569 const progress = Math.round(size * percentage); 570 const emptyProgress = size - progress; 571 const progressText = "โ".repeat(progress); 572 const emptyProgressText = "โ".repeat(emptyProgress); 573 const percentageText = Math.round(percentage * 100) + "%"; 574 575 const Bar = progressText + emptyProgressText; 576 return { Bar, percentageText }; 577 } 578 function prettyMs(milliseconds, options = {}) { 579 const pluralize = (word, count) => (count === 1 ? word : `${word}s`); 580 const SECOND_ROUNDING_EPSILON = 0.0000001; 581 if (!Number.isFinite(milliseconds)) { 582 throw new TypeError("Expected a finite number"); 583 } 584 585 if (options.colonNotation) { 586 options.compact = false; 587 options.formatSubMilliseconds = false; 588 options.separateMilliseconds = false; 589 options.verbose = false; 590 } 591 592 if (options.compact) { 593 options.secondsDecimalDigits = 0; 594 options.millisecondsDecimalDigits = 0; 595 } 596 597 const result = []; 598 599 const floorDecimals = (value, decimalDigits) => { 600 const flooredInterimValue = Math.floor( 601 value * 10 ** decimalDigits + SECOND_ROUNDING_EPSILON 602 ); 603 const flooredValue = Math.round(flooredInterimValue) / 10 ** decimalDigits; 604 return flooredValue.toFixed(decimalDigits); 605 }; 606 607 const add = (value, long, short, valueString) => { 608 if ( 609 (result.length === 0 || !options.colonNotation) && 610 value === 0 && 611 !(options.colonNotation && short === "m") 612 ) { 613 return; 614 } 615 616 valueString = (valueString || value || "0").toString(); 617 let prefix; 618 let suffix; 619 if (options.colonNotation) { 620 prefix = result.length > 0 ? ":" : ""; 621 suffix = ""; 622 const wholeDigits = valueString.includes(".") 623 ? valueString.split(".")[0].length 624 : valueString.length; 625 const minLength = result.length > 0 ? 2 : 1; 626 valueString = 627 "0".repeat(Math.max(0, minLength - wholeDigits)) + valueString; 628 } else { 629 prefix = ""; 630 suffix = options.verbose ? " " + pluralize(long, value) : short; 631 } 632 633 result.push(prefix + valueString + suffix); 634 }; 635 636 const parsed = parseMilliseconds(milliseconds); 637 638 add(Math.trunc(parsed.days / 365), "year", "y"); 639 add(parsed.days % 365, "day", "d"); 640 add(parsed.hours, "hour", "h"); 641 add(parsed.minutes, "minute", "m"); 642 643 if ( 644 options.separateMilliseconds || 645 options.formatSubMilliseconds || 646 (!options.colonNotation && milliseconds < 1000) 647 ) { 648 add(parsed.seconds, "second", "s"); 649 if (options.formatSubMilliseconds) { 650 add(parsed.milliseconds, "millisecond", "ms"); 651 add(parsed.microseconds, "microsecond", "ยตs"); 652 add(parsed.nanoseconds, "nanosecond", "ns"); 653 } else { 654 const millisecondsAndBelow = 655 parsed.milliseconds + 656 parsed.microseconds / 1000 + 657 parsed.nanoseconds / 1e6; 658 659 const millisecondsDecimalDigits = 660 typeof options.millisecondsDecimalDigits === "number" 661 ? options.millisecondsDecimalDigits 662 : 0; 663 664 const roundedMiliseconds = 665 millisecondsAndBelow >= 1 666 ? Math.round(millisecondsAndBelow) 667 : Math.ceil(millisecondsAndBelow); 668 669 const millisecondsString = millisecondsDecimalDigits 670 ? millisecondsAndBelow.toFixed(millisecondsDecimalDigits) 671 : roundedMiliseconds; 672 673 add( 674 Number.parseFloat(millisecondsString, 10), 675 "millisecond", 676 "ms", 677 millisecondsString 678 ); 679 } 680 } else { 681 const seconds = (milliseconds / 1000) % 60; 682 const secondsDecimalDigits = 683 typeof options.secondsDecimalDigits === "number" 684 ? options.secondsDecimalDigits 685 : 1; 686 const secondsFixed = floorDecimals(seconds, secondsDecimalDigits); 687 const secondsString = options.keepDecimalsOnWholeSeconds 688 ? secondsFixed 689 : secondsFixed.replace(/\.0+$/, ""); 690 add(Number.parseFloat(secondsString, 10), "second", "s", secondsString); 691 } 692 693 if (result.length === 0) { 694 return "0" + (options.verbose ? " milliseconds" : "ms"); 695 } 696 697 if (options.compact) { 698 return result[0]; 699 } 700 701 if (typeof options.unitCount === "number") { 702 const separator = options.colonNotation ? "" : " "; 703 return result.slice(0, Math.max(options.unitCount, 1)).join(separator); 704 } 705 706 return options.colonNotation ? result.join("") : result.join(" "); 707 } 708 function parseMilliseconds(milliseconds) { 709 if (typeof milliseconds !== "number") { 710 throw new TypeError("Expected a number"); 711 } 712 713 return { 714 days: Math.trunc(milliseconds / 86400000), 715 hours: Math.trunc(milliseconds / 3600000) % 24, 716 minutes: Math.trunc(milliseconds / 60000) % 60, 717 seconds: Math.trunc(milliseconds / 1000) % 60, 718 milliseconds: Math.trunc(milliseconds) % 1000, 719 microseconds: Math.trunc(milliseconds * 1000) % 1000, 720 nanoseconds: Math.trunc(milliseconds * 1e6) % 1000, 721 }; 722 } 723 const default_opts = { 724 hoursPerDay: 24, 725 daysPerWeek: 7, 726 weeksPerMonth: 4, 727 monthsPerYear: 12, 728 daysPerYear: 365.25, 729 }; 730 const UNIT_MAP = { 731 ms: ["ms", "milli", "millisecond", "milliseconds"], 732 s: ["s", "sec", "secs", "second", "seconds"], 733 m: ["m", "min", "mins", "minute", "minutes"], 734 h: ["h", "hr", "hrs", "hour", "hours"], 735 d: ["d", "day", "days"], 736 w: ["w", "week", "weeks"], 737 mth: ["mon", "mth", "mths", "month", "months"], 738 y: ["y", "yr", "yrs", "year", "years"], 739 }; 740 741 /** 742 * Parse a timestring 743 * 744 * @param {string} string 745 * @param {string} returnUnit 746 * @param {Object} opts 747 * @returns {number} 748 */ 749 750 function parseTimestring(string, returnUnit, opts) { 751 opts = Object.assign({}, default_opts, opts || {}); 752 753 let totalSeconds = 0; 754 const unitValues = getUnitValues(opts); 755 const groups = string 756 .toLowerCase() 757 .replace(/[^.\w+-]+/g, "") 758 .match(/[-+]?[0-9.]+[a-z]+/g); 759 760 if (groups === null) { 761 throw new Error(`The string [${string}] could not be parsed by timestring`); 762 } 763 764 groups.forEach(group => { 765 const value = group.match(/[0-9.]+/g)[0]; 766 const unit = group.match(/[a-z]+/g)[0]; 767 768 totalSeconds += getSeconds(value, unit, unitValues); 769 }); 770 771 if (returnUnit) { 772 return convert(totalSeconds, returnUnit, unitValues); 773 } 774 775 return totalSeconds; 776 } 777 function getUnitValues(opts) { 778 const unitValues = { 779 ms: 0.001, 780 s: 1, 781 m: 60, 782 h: 3600, 783 }; 784 785 unitValues.d = opts.hoursPerDay * unitValues.h; 786 unitValues.w = opts.daysPerWeek * unitValues.d; 787 unitValues.mth = (opts.daysPerYear / opts.monthsPerYear) * unitValues.d; 788 unitValues.y = opts.daysPerYear * unitValues.d; 789 790 return unitValues; 791 } 792 function getUnitKey(unit) { 793 for (const key of Object.keys(UNIT_MAP)) { 794 if (UNIT_MAP[key].indexOf(unit) > -1) { 795 return key; 796 } 797 } 798 throw new Error(`The unit [${unit}] is not supported by timestring`); 799 } 800 function getSeconds(value, unit, unitValues) { 801 return value * unitValues[getUnitKey(unit)]; 802 } 803 function convert(value, unit, unitValues) { 804 return value / unitValues[getUnitKey(unit)]; 805 } 806 807 module.exports = { 808 rndint, 809 parseDate, 810 parseShortDate, 811 timer, 812 sleep, 813 toHHMMSS, 814 fixPermissions, 815 trimArray, 816 formatPerms, 817 checkDays, 818 format, 819 fixFeatures, 820 cooldown, 821 ms, 822 confirmation, 823 selectRandom, 824 getAllTextFromEmbed, 825 clean, 826 tips, 827 inviteLink, 828 buttons, 829 colorize, 830 leven, 831 chunk, 832 progressBar, 833 parseTimestring, 834 prettyMs, 835 };