1
0
mirror of https://github.com/toast-ts/Daggerbot-TS.git synced 2024-11-17 04:10:59 -05:00

Move essentials out of client.ts

This commit is contained in:
AnxietyisReal 2023-08-30 18:34:59 +10:00
parent de7169035f
commit 793c22dbcd
21 changed files with 176 additions and 162 deletions

View File

@ -1,6 +1,6 @@
import Discord, {Client, GatewayIntentBits, Partials} from 'discord.js'; import Discord from 'discord.js';
import {readFileSync, readdirSync} from 'node:fs'; import {readFileSync, readdirSync} from 'node:fs';
import {formatTimeOpt, Tokens, Config, repeatedMessages, type MPServerCache} from './typings/interfaces'; import {Tokens, Config, repeatedMessages, type MPServerCache} from './typings/interfaces';
import bannedWords from './models/bannedWords.js'; import bannedWords from './models/bannedWords.js';
import userLevels from './models/userLevels.js'; import userLevels from './models/userLevels.js';
import suggestion from './models/suggestion.js'; import suggestion from './models/suggestion.js';
@ -23,7 +23,7 @@ try{
console.log('Using production config') console.log('Using production config')
} }
export default class TClient extends Client { export default class TClient extends Discord.Client {
invites: Map<any, any>; invites: Map<any, any>;
commands: Discord.Collection<string, any>; commands: Discord.Collection<string, any>;
registry: Array<Discord.ApplicationCommandDataResolvable>; registry: Array<Discord.ApplicationCommandDataResolvable>;
@ -36,7 +36,6 @@ export default class TClient extends Client {
attachmentBuilder: any; attachmentBuilder: any;
moment: typeof moment; moment: typeof moment;
xjs: typeof xjs; xjs: typeof xjs;
ms: any;
userLevels: userLevels; userLevels: userLevels;
punishments: punishments; punishments: punishments;
bonkCount: bonkCount; bonkCount: bonkCount;
@ -51,13 +50,13 @@ export default class TClient extends Client {
constructor(){ constructor(){
super({ super({
intents: [ intents: [
GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, Discord.GatewayIntentBits.Guilds, Discord.GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildModeration, GatewayIntentBits.GuildInvites, Discord.GatewayIntentBits.GuildModeration, Discord.GatewayIntentBits.GuildInvites,
GatewayIntentBits.GuildMessageReactions, GatewayIntentBits.GuildPresences, Discord.GatewayIntentBits.GuildMessageReactions, Discord.GatewayIntentBits.GuildPresences,
GatewayIntentBits.MessageContent, GatewayIntentBits.GuildMessages, Discord.GatewayIntentBits.MessageContent, Discord.GatewayIntentBits.GuildMessages,
GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.DirectMessages Discord.GatewayIntentBits.GuildVoiceStates, Discord.GatewayIntentBits.DirectMessages
], partials: [ ], partials: [
Partials.Channel, Partials.Reaction, Partials.Message Discord.Partials.Channel, Discord.Partials.Reaction, Discord.Partials.Message
], allowedMentions: {users:[],roles:[]} ], allowedMentions: {users:[],roles:[]}
}) })
this.invites = new Map(); this.invites = new Map();
@ -75,7 +74,6 @@ export default class TClient extends Client {
this.attachmentBuilder = Discord.AttachmentBuilder; this.attachmentBuilder = Discord.AttachmentBuilder;
this.moment = moment; this.moment = moment;
this.xjs = xjs; this.xjs = xjs;
this.ms = import('ms').then(i=>i);
this.userLevels = new userLevels(this); this.userLevels = new userLevels(this);
this.bonkCount = new bonkCount(this); this.bonkCount = new bonkCount(this);
this.punishments = new punishments(this); this.punishments = new punishments(this);
@ -109,106 +107,7 @@ export default class TClient extends Client {
} }
} }
} }
formatTime(integer: number, accuracy = 1, options?: formatTimeOpt){
let achievedAccuracy = 0;
let text:any = '';
for (const timeName of [
{name: 'year', length: 31536000000},
{name: 'month', length: 2592000000},
{name: 'week', length: 604800000},
{name: 'day', length: 86400000},
{name: 'hour', length: 3600000},
{name: 'minute', length: 60000},
{name: 'second', length: 1000}
]){
if (achievedAccuracy < accuracy){
const fullTimelengths = Math.floor(integer/timeName.length);
if (fullTimelengths === 0) continue;
achievedAccuracy++;
text += fullTimelengths + (options?.longNames ? (' '+timeName.name+(fullTimelengths === 1 ? '' : 's')) : timeName.name.slice(0, timeName.name === 'month' ? 2 : 1)) + (options?.commas ? ', ' : ' ');
integer -= fullTimelengths*timeName.length;
} else break;
}
if (text.length == 0) text = integer + (options?.longNames ? ' milliseconds' : 'ms') + (options?.commas ? ', ' : '');
if (options?.commas){
text = text.slice(0, -2);
if (options?.longNames){
text = text.split('');
text[text.lastIndexOf(',')] = ' and';
text = text.join('');
}
} return text.trim();
}
formatPlayerUptime(oldTime:number){
var Hours=0;
oldTime=Math.floor(Number(oldTime));
if(oldTime>=60){
var Hours=Math.floor(Number(oldTime)/60);
var Minutes=(Number(oldTime)-(Hours*60));
} else Minutes=Number(oldTime)
if(Hours>=24){
var Days=Math.floor(Number(Hours)/24);
var Hours=(Hours-(Days*24));
} return (Days>0?Days+' d ':'')+(Hours>0?Hours+' h ':'')+(Minutes>0?Minutes+' m':'')
}
isStaff = (guildMember:Discord.GuildMember)=>this.config.mainServer.staffRoles.map((x: string)=>this.config.mainServer.roles[x]).some((x: string)=>guildMember.roles.cache.has(x)); isStaff = (guildMember:Discord.GuildMember)=>this.config.mainServer.staffRoles.map((x: string)=>this.config.mainServer.roles[x]).some((x: string)=>guildMember.roles.cache.has(x));
youNeedRole = (interaction:Discord.CommandInteraction, role:string)=>interaction.reply(`This command is restricted to <@&${this.config.mainServer.roles[role]}>`); youNeedRole = (interaction:Discord.CommandInteraction, role:string)=>interaction.reply(`This command is restricted to <@&${this.config.mainServer.roles[role]}>`);
logTime = ()=>`[${this.moment().format('DD/MM/YY HH:mm:ss')}]`; logTime = ()=>`[${this.moment().format('DD/MM/YY HH:mm:ss')}]`;
async punish(interaction: Discord.ChatInputCommandInteraction<'cached'>, type: string){
if (!this.isStaff(interaction.member as Discord.GuildMember)) return this.youNeedRole(interaction, "dcmod");
const time = interaction.options.getString('time') ?? undefined;
const reason = interaction.options.getString('reason') ?? 'Reason unspecified';
const GuildMember = interaction.options.getMember('member') ?? undefined;
const User = interaction.options.getUser('member', true);
console.log(this.logTime(), `[PunishmentLog] ${GuildMember?.user?.username ?? User?.username ?? 'No user data'} ${time ? ['warn', 'kick'].includes(this.punishments.type) ? 'and no duration set' : `and ${time} (duration)` : ''} was used in /${interaction.commandName} for ${reason}`);
(this.channels.cache.get(this.config.mainServer.channels.punishment_log) as Discord.TextChannel).send({embeds:[new this.embed().setColor(this.config.embedColor).setAuthor({name: interaction?.user?.username, iconURL: interaction?.user?.displayAvatarURL({size:2048})}).setTitle('Punishment Log').setDescription(`${GuildMember?.user?.username ?? User?.username ?? 'No user data'} ${time ? ['warn', 'kick'].includes(this.punishments.type) ? 'and no duration set' : `and ${time} (duration)` : ''} was used in \`/${interaction.commandName}\` for \`${reason}\``).setTimestamp()]});
if (interaction.user.id === User.id) return interaction.reply(`You cannot ${type} yourself.`);
if (!GuildMember && type != 'unban') return interaction.reply(`You cannot ${type} someone who is not in the server.`);
if (User.bot) return interaction.reply(`You cannot ${type} a bot!`);
await interaction.deferReply();
await this.punishments.addPunishment(type, { time, interaction }, interaction.user.id, reason, User, GuildMember);
}
async YTLoop(YTChannelID: string, YTChannelName: string, DCChannelID: string){
let Data:any;
try {
await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {signal: AbortSignal.timeout(6000),headers:{'User-Agent':`Daggerbot - Notification/undici`}}).then(async xml=>Data = this.xjs.xml2js(await xml.text(), {compact: true}))
} catch(err){
console.log(this.logTime(), `${YTChannelName} YT fail`)
}
if (!Data) return;
if (!this.YTCache[YTChannelID]) return this.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text;
if (Data.feed.entry[1]['yt:videoId']._text === this.YTCache[YTChannelID]){
this.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text;
(this.channels.resolve(DCChannelID) as Discord.TextChannel).send(`**${YTChannelName}** just uploaded a video!\n${Data.feed.entry[0].link._attributes.href}`)
}
}
formatBytes(bytes:number, decimals:number = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals < 0 ? 0 : decimals)) + ' ' + ['Bytes', 'KB', 'MB', 'GB'][i];
}
removeUsername = (text: string)=>{
let matchesLeft = true;
const dirSlash = process.platform === 'linux' ? '\/' : '\\';
const array = text.split(dirSlash);
while (matchesLeft){
let usersIndex = array.indexOf(process.platform === 'linux' ? 'home' : 'Users');
if (usersIndex<1) matchesLeft = false;
else {
let usernameIndex = usersIndex+1;
if(array[usernameIndex].length == 0) usernameIndex += 1;
array[usernameIndex] = '・'.repeat(array[usernameIndex].length);
array[usersIndex] = process.platform === 'linux' ? 'ho\u200bme' : 'Us\u200bers';
}
} return array.join(dirSlash);
}
} }

View File

@ -1,8 +1,9 @@
import Discord from 'discord.js'; import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import Punish from '../funcs/Punish.js';
export default { export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'ban'); Punish(client, interaction, 'ban');
}, },
data: new Discord.SlashCommandBuilder() data: new Discord.SlashCommandBuilder()
.setName('ban') .setName('ban')

View File

@ -1,5 +1,6 @@
import Discord from "discord.js"; import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import FormatTime from '../helpers/FormatTime.js';
export default { export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (!client.isStaff(interaction.member)) return client.youNeedRole(interaction, 'dcmod'); if (!client.isStaff(interaction.member)) return client.youNeedRole(interaction, 'dcmod');
@ -21,7 +22,7 @@ export default {
{name: '🔹 Moderator', value: `<@${punishment.moderator}> \`${punishment.moderator}\``, inline: true}, {name: '🔹 Moderator', value: `<@${punishment.moderator}> \`${punishment.moderator}\``, inline: true},
{name: '\u200b', value: '\u200b', inline: true}, {name: '\u200b', value: '\u200b', inline: true},
{name: '🔹 Reason', value: `\`${punishment.reason || 'Reason unspecified'}\``, inline: true}) {name: '🔹 Reason', value: `\`${punishment.reason || 'Reason unspecified'}\``, inline: true})
if (punishment.duration) embed.addFields({name: '🔹 Duration', value: client.formatTime(punishment.duration, 100)}) if (punishment.duration) embed.addFields({name: '🔹 Duration', value: `${FormatTime(punishment.duration, 100)}`})
if (punishment.expired) embed.addFields({name: '🔹 Expired', value: `This case has been overwritten by Case #${cancelledBy.id} for reason \`${cancelledBy.reason}\``}) if (punishment.expired) embed.addFields({name: '🔹 Expired', value: `This case has been overwritten by Case #${cancelledBy.id} for reason \`${cancelledBy.reason}\``})
if (punishment.cancels) embed.addFields({name: '🔹 Overwrites', value: `This case overwrites Case #${cancels.id} with reason \`${cancels.reason}\``}) if (punishment.cancels) embed.addFields({name: '🔹 Overwrites', value: `This case overwrites Case #${cancels.id} with reason \`${cancels.reason}\``})
interaction.reply({embeds: [embed]}); interaction.reply({embeds: [embed]});
@ -34,7 +35,7 @@ export default {
const userPunishment = userPunishmentData.sort((a,b)=>a.time-b.time).map((punishment)=>{ const userPunishment = userPunishmentData.sort((a,b)=>a.time-b.time).map((punishment)=>{
return { return {
name: `${punishment.type[0].toUpperCase()+punishment.type.slice(1)} | Case #${punishment.id}`, name: `${punishment.type[0].toUpperCase()+punishment.type.slice(1)} | Case #${punishment.id}`,
value: `Reason: \`${punishment.reason}\`\n${punishment.duration ? `Duration: ${client.formatTime(punishment.duration, 3)}\n` : ''}Moderator: <@${punishment.moderator}>${punishment.expired ? `\nOverwritten by Case #${punishments.find(x=>x.cancels===punishment._id)?._id}` : ''}${punishment.cancels ? `\nOverwrites Case #${punishment.cancels}` : ''}` value: `Reason: \`${punishment.reason}\`\n${punishment.duration ? `Duration: ${FormatTime(punishment.duration, 3)}\n` : ''}Moderator: <@${punishment.moderator}>${punishment.expired ? `\nOverwritten by Case #${punishments.find(x=>x.cancels===punishment._id)?._id}` : ''}${punishment.cancels ? `\nOverwrites Case #${punishment.cancels}` : ''}`
} }
}); });
if (!punishments || !userPunishment) return interaction.reply(`**${user.username}** has a clean record.`) if (!punishments || !userPunishment) return interaction.reply(`**${user.username}** has a clean record.`)

View File

@ -3,6 +3,8 @@ import {Octokit} from '@octokit/rest';
import {createTokenAuth} from '@octokit/auth-token'; import {createTokenAuth} from '@octokit/auth-token';
import {exec} from 'node:child_process'; import {exec} from 'node:child_process';
import MessageTool from '../helpers/MessageTool.js'; import MessageTool from '../helpers/MessageTool.js';
import UsernameHelper from '../helpers/UsernameHelper.js';
import FormatTime from '../helpers/FormatTime.js';
import fs from 'node:fs'; import fs from 'node:fs';
import util from 'node:util'; import util from 'node:util';
import TClient from '../client.js'; import TClient from '../client.js';
@ -27,7 +29,7 @@ export default {
const filter = (x:any)=>x.content === 'stack' && x.author.id === interaction.user.id const filter = (x:any)=>x.content === 'stack' && x.author.id === interaction.user.id
const messagecollector = (interaction.channel as Discord.TextChannel).createMessageCollector({filter, max: 1, time: 60000}); const messagecollector = (interaction.channel as Discord.TextChannel).createMessageCollector({filter, max: 1, time: 60000});
messagecollector.on('collect', collected=>{ messagecollector.on('collect', collected=>{
collected.reply({content: `\`\`\`\n${client.removeUsername(err.stack)}\n\`\`\``, allowedMentions: {repliedUser: false}}); collected.reply({content: `\`\`\`\n${UsernameHelper.stripName(err.stack)}\n\`\`\``, allowedMentions: {repliedUser: false}});
}); });
}); });
} }
@ -40,7 +42,7 @@ export default {
].forEach(x=>output = output.replace(new RegExp(x as string,'g'),':noblank: No token?')); ].forEach(x=>output = output.replace(new RegExp(x as string,'g'),':noblank: No token?'));
const embed = new client.embed().setColor(client.config.embedColor).setTitle('__Eval__').addFields( const embed = new client.embed().setColor(client.config.embedColor).setTitle('__Eval__').addFields(
{name: 'Input', value: `\`\`\`js\n${code.slice(0,1010)}\n\`\`\``}, {name: 'Input', value: `\`\`\`js\n${code.slice(0,1010)}\n\`\`\``},
{name: 'Output', value: `\`\`\`${client.removeUsername(output).slice(0,1016)}\n\`\`\``} {name: 'Output', value: `\`\`\`${UsernameHelper.stripName(output).slice(0,1016)}\n\`\`\``}
); );
interaction.reply({embeds: [embed]}).catch(()=>(interaction.channel as Discord.TextChannel).send({embeds: [embed]})); interaction.reply({embeds: [embed]}).catch(()=>(interaction.channel as Discord.TextChannel).send({embeds: [embed]}));
}, },
@ -63,11 +65,11 @@ export default {
} }
}; };
exec('git pull',{windowsHide:true},(err:Error,stdout)=>{ exec('git pull',{windowsHide:true},(err:Error,stdout)=>{
if (err) clarkson.edit(`\`\`\`${client.removeUsername(err.message)}\`\`\``) if (err) clarkson.edit(`\`\`\`${UsernameHelper.stripName(err.message)}\`\`\``)
else if (stdout.includes('Already up to date')) clarkson.edit('I am already up to date with the upstream repository.') else if (stdout.includes('Already up to date')) clarkson.edit('I am already up to date with the upstream repository.')
else clarkson.edit('Compiling TypeScript files...').then(()=>exec('yarn tsc', {windowsHide:true}, (err:Error)=>{ else clarkson.edit('Compiling TypeScript files...').then(()=>exec('yarn tsc', {windowsHide:true}, (err:Error)=>{
if (err) clarkson.edit(`\`\`\`${client.removeUsername(err.message)}\`\`\``) if (err) clarkson.edit(`\`\`\`${UsernameHelper.stripName(err.message)}\`\`\``)
if (interaction.options.getBoolean('restart')) clarkson.edit(`[Commit:](<${github.fetchCommit.url}>) **${github.fetchCommit.msg}**\nCommit author: **${github.fetchCommit.author}**\n\n__Commit changes__\nTotal: **${github.fetchChanges.total}**\nAdditions: **${github.fetchChanges.addition}**\nDeletions: **${github.fetchChanges.deletion}**\n\nSuccessfully compiled TypeScript files into JavaScript!\nUptime before restarting: **${client.formatTime(client.uptime, 3, {commas: true, longNames: true})}**`).then(()=>exec('pm2 restart Daggerbot', {windowsHide:true})); if (interaction.options.getBoolean('restart')) clarkson.edit(`[Commit:](<${github.fetchCommit.url}>) **${github.fetchCommit.msg}**\nCommit author: **${github.fetchCommit.author}**\n\n__Commit changes__\nTotal: **${github.fetchChanges.total}**\nAdditions: **${github.fetchChanges.addition}**\nDeletions: **${github.fetchChanges.deletion}**\n\nSuccessfully compiled TypeScript files into JavaScript!\nUptime before restarting: **${FormatTime(client.uptime, 3, {commas: true, longNames: true})}**`).then(()=>exec('pm2 restart Daggerbot', {windowsHide:true}));
else clarkson.edit(`[Commit:](<${github.fetchCommit.url}>) **${github.fetchCommit.msg}**\nCommit author: **${github.fetchCommit.author}**\n\n__Commit changes__\nTotal: **${github.fetchChanges.total}**\nAdditions: **${github.fetchChanges.addition}**\nDeletions: **${github.fetchChanges.deletion}**\n\nSuccessfully compiled TypeScript files into JavaScript!`) else clarkson.edit(`[Commit:](<${github.fetchCommit.url}>) **${github.fetchCommit.msg}**\nCommit author: **${github.fetchCommit.author}**\n\n__Commit changes__\nTotal: **${github.fetchChanges.total}**\nAdditions: **${github.fetchChanges.addition}**\nDeletions: **${github.fetchChanges.deletion}**\n\nSuccessfully compiled TypeScript files into JavaScript!`)
})) }))
}) })
@ -112,15 +114,15 @@ export default {
restart: async()=>{ restart: async()=>{
const i = await interaction.reply({content: 'Compiling TypeScript files...', fetchReply: true}); const i = await interaction.reply({content: 'Compiling TypeScript files...', fetchReply: true});
exec('yarn tsc',{windowsHide:true},(err:Error)=>{ exec('yarn tsc',{windowsHide:true},(err:Error)=>{
if (err) i.edit(`\`\`\`${client.removeUsername(err.message)}\`\`\``) if (err) i.edit(`\`\`\`${UsernameHelper.stripName(err.message)}\`\`\``)
else i.edit(`Successfully compiled TypeScript files into JavaScript!\nUptime before restarting: **${client.formatTime(client.uptime, 3, {commas: true, longNames: true})}**`).then(()=>exec('pm2 restart Daggerbot', {windowsHide:true})) else i.edit(`Successfully compiled TypeScript files into JavaScript!\nUptime before restarting: **${FormatTime(client.uptime, 3, {commas: true, longNames: true})}**`).then(()=>exec('pm2 restart Daggerbot', {windowsHide:true}))
}) })
}, },
file: ()=>interaction.reply({files:[`./src/database/${interaction.options.getString('name')}.json`]}).catch(()=>'Filesize is too large, upload cancelled.'), file: ()=>interaction.reply({files:[`./src/database/${interaction.options.getString('name')}.json`]}).catch(()=>'Filesize is too large, upload cancelled.'),
wake_device: async()=>{ wake_device: async()=>{
const i = await interaction.reply({content: 'Spawning a task...', fetchReply: true}); const i = await interaction.reply({content: 'Spawning a task...', fetchReply: true});
exec(`cd "../../Desktop/System Tools/wakemeonlan" && WakeMeOnLan.exe /wakeup ${interaction.options.getString('name')}`, {windowsHide:true}, (err:Error)=>{ exec(`cd "../../Desktop/System Tools/wakemeonlan" && WakeMeOnLan.exe /wakeup ${interaction.options.getString('name')}`, {windowsHide:true}, (err:Error)=>{
if (err) i.edit(client.removeUsername(err.message)) if (err) i.edit(UsernameHelper.stripName(err.message))
else i.edit('Your device should be awake by now!\n||Don\'t blame me if it isn\'t on.||') else i.edit('Your device should be awake by now!\n||Don\'t blame me if it isn\'t on.||')
}) })
} }

View File

@ -1,8 +1,9 @@
import Discord from 'discord.js'; import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import Punish from '../funcs/Punish.js';
export default { export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'kick'); Punish(client, interaction, 'kick');
}, },
data: new Discord.SlashCommandBuilder() data: new Discord.SlashCommandBuilder()
.setName('kick') .setName('kick')

View File

@ -2,9 +2,10 @@ import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import path from 'node:path'; import path from 'node:path';
import canvas from 'canvas'; import canvas from 'canvas';
import FormatPlayer from '../helpers/FormatPlayer.js';
import MessageTool from '../helpers/MessageTool.js'; import MessageTool from '../helpers/MessageTool.js';
import {readFileSync} from 'node:fs'; import {readFileSync} from 'node:fs';
import {FSData} from 'src/typings/interfaces.js'; import {FSData} from '../typings/interfaces.js';
const serverChoices = [ const serverChoices = [
{name: 'Main Server', value: 'mainServer'}, {name: 'Main Server', value: 'mainServer'},
@ -149,11 +150,7 @@ export default {
else if (endpoint.slots.used > 8) Color = client.config.embedColorYellow; else if (endpoint.slots.used > 8) Color = client.config.embedColorYellow;
else Color = client.config.embedColorGreen; else Color = client.config.embedColorGreen;
for (const player of endpoint.slots.players.filter(x=>x.isUsed)){ for (const player of endpoint.slots.players.filter(x=>x.isUsed)) playerData.push(`**${player.name}${FormatPlayer.decoratePlayerIcons(player)}**\nFarming for ${FormatPlayer.uptimeFormat(player.uptime)}`)
let decorator = player.isAdmin ? ':detective:' : '';
decorator += player.name.includes('Toast') ? '<:toastv2:1132681026662056079>' : '';
playerData.push(`**${player.name}${decorator}**\nFarming for ${client.formatPlayerUptime(player.uptime)}`)
}
const slot = `${endpoint.slots.used}/${endpoint.slots.capacity}`; const slot = `${endpoint.slots.used}/${endpoint.slots.capacity}`;
const ingameTime = `${('0'+Math.floor((endpoint.server.dayTime/3600/1000))).slice(-2)}:${('0'+Math.floor((endpoint.server.dayTime/60/1000)%60)).slice(-2)}`; const ingameTime = `${('0'+Math.floor((endpoint.server.dayTime/3600/1000))).slice(-2)}:${('0'+Math.floor((endpoint.server.dayTime/60/1000)%60)).slice(-2)}`;

View File

@ -1,8 +1,9 @@
import Discord from 'discord.js'; import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import Punish from '../funcs/Punish.js';
export default { export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'mute'); Punish(client, interaction, 'mute');
}, },
data: new Discord.SlashCommandBuilder() data: new Discord.SlashCommandBuilder()
.setName('mute') .setName('mute')

View File

@ -1,10 +1,11 @@
import Discord from 'discord.js'; import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import FormatTime from '../helpers/FormatTime.js';
export default { export default {
async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ async run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
if (client.uptime < 15500) return interaction.reply('I just restarted, wait 15 seconds and try again.') if (client.uptime < 15500) return interaction.reply('I just restarted, wait 15 seconds and try again.')
const msg = await interaction.reply({content: 'Pinging...', fetchReply: true}) const msg = await interaction.reply({content: 'Pinging...', fetchReply: true})
msg.edit(`API Latency: \`${client.formatTime(client.ws.ping, 3, {longNames: false, commas: true})}\`\nBot Latency: \`${client.formatTime(msg.createdTimestamp - interaction.createdTimestamp, 3, {longNames: false, commas: true})}\``) msg.edit(`API Latency: \`${FormatTime(client.ws.ping, 3, {longNames: false, commas: true})}\`\nBot Latency: \`${FormatTime(msg.createdTimestamp - interaction.createdTimestamp, 3, {longNames: false, commas: true})}\``)
}, },
data: new Discord.SlashCommandBuilder() data: new Discord.SlashCommandBuilder()
.setName('ping') .setName('ping')

View File

@ -1,8 +1,9 @@
import Discord from 'discord.js'; import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import Punish from '../funcs/Punish.js';
export default { export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'softban'); Punish(client, interaction, 'softban');
}, },
data: new Discord.SlashCommandBuilder() data: new Discord.SlashCommandBuilder()
.setName('softban') .setName('softban')

View File

@ -1,6 +1,8 @@
import Discord from 'discord.js'; import Discord from 'discord.js';
import pkg from 'typescript'; import pkg from 'typescript';
import MessageTool from '../helpers/MessageTool.js'; import MessageTool from '../helpers/MessageTool.js';
import FormatBytes from '../helpers/FormatBytes.js';
import FormatTime from '../helpers/FormatTime.js';
import si from 'systeminformation'; import si from 'systeminformation';
import TClient from '../client.js'; import TClient from '../client.js';
import os from 'node:os'; import os from 'node:os';
@ -16,7 +18,7 @@ export default {
const columns = ['Command name', 'Count']; const columns = ['Command name', 'Count'];
const includedCommands = client.commands.filter(x=>x.uses).sort((a,b)=>b.uses - a.uses); const includedCommands = client.commands.filter(x=>x.uses).sort((a,b)=>b.uses - a.uses);
if (includedCommands.size === 0) return interaction.reply(`No commands have been used yet.\nUptime: **${client.formatTime(client.uptime, 3, {longNames: true, commas: true})}**`); if (includedCommands.size === 0) return interaction.reply(`No commands have been used yet.\nUptime: **${FormatTime(client.uptime, 3, {longNames: true, commas: true})}**`);
const nameLength = Math.max(...includedCommands.map(x=>x.command.default.data.name.length), columns[0].length) + 2; const nameLength = Math.max(...includedCommands.map(x=>x.command.default.data.name.length), columns[0].length) + 2;
const amountLength = Math.max(...includedCommands.map(x=>x.uses.toString().length), columns[1].length) + 1; const amountLength = Math.max(...includedCommands.map(x=>x.uses.toString().length), columns[1].length) + 1;
const rows = [`${columns[0] + ' '.repeat(nameLength - columns[0].length)}|${' '.repeat(amountLength - columns[1].length) + columns[1]}\n`, '-'.repeat(nameLength) + '-'.repeat(amountLength) + '\n']; const rows = [`${columns[0] + ' '.repeat(nameLength - columns[0].length)}|${' '.repeat(amountLength - columns[1].length) + columns[1]}\n`, '-'.repeat(nameLength) + '-'.repeat(amountLength) + '\n'];
@ -50,13 +52,13 @@ export default {
{name: '> __Host__', value: MessageTool.concatMessage( {name: '> __Host__', value: MessageTool.concatMessage(
`**Operating System:** ${osInfo.distro + ' ' + osInfo.release}`, `**Operating System:** ${osInfo.distro + ' ' + osInfo.release}`,
`**CPU:** ${cpu.manufacturer} ${cpu.brand}`, `**CPU:** ${cpu.manufacturer} ${cpu.brand}`,
`**Memory:** ${client.formatBytes(ram.used)}/${client.formatBytes(ram.total)}`, `**Memory:** ${FormatBytes(ram.used)}/${FormatBytes(ram.total)}`,
`**Process:** ${client.formatBytes(process.memoryUsage().heapUsed)}/${client.formatBytes(process.memoryUsage().heapTotal)}`, `**Process:** ${FormatBytes(process.memoryUsage().heapUsed)}/${FormatBytes(process.memoryUsage().heapTotal)}`,
`**Load Usage:**\nUser: ${currentLoad.currentLoadUser.toFixed(1)}%\nSystem: ${currentLoad.currentLoadSystem.toFixed(1)}%`, `**Load Usage:**\nUser: ${currentLoad.currentLoadUser.toFixed(1)}%\nSystem: ${currentLoad.currentLoadSystem.toFixed(1)}%`,
`**Uptime:**\nHost: ${client.formatTime((os.uptime()*1000), 2, {longNames: true, commas: true})}\nBot: ${client.formatTime(client.uptime, 2, {commas: true, longNames: true})}` `**Uptime:**\nHost: ${FormatTime((os.uptime()*1000), 2, {longNames: true, commas: true})}\nBot: ${FormatTime(client.uptime, 2, {commas: true, longNames: true})}`
)} )}
); );
waitForData.edit({content:null,embeds:[embed]}).then(x=>x.edit({embeds:[new client.embed(x.embeds[0].data).setFooter({text: `Load time: ${client.formatTime(x.createdTimestamp - interaction.createdTimestamp, 2, {longNames: true, commas: true})}`})]})) waitForData.edit({content:null,embeds:[embed]}).then(x=>x.edit({embeds:[new client.embed(x.embeds[0].data).setFooter({text: `Load time: ${FormatTime(x.createdTimestamp - interaction.createdTimestamp, 2, {longNames: true, commas: true})}`})]}))
}, },
data: new Discord.SlashCommandBuilder() data: new Discord.SlashCommandBuilder()
.setName('statistics') .setName('statistics')

View File

@ -1,8 +1,9 @@
import Discord from 'discord.js'; import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import Punish from '../funcs/Punish.js';
export default { export default {
run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){ run(client: TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>){
client.punish(interaction, 'warn'); Punish(client, interaction, 'warn');
}, },
data: new Discord.SlashCommandBuilder() data: new Discord.SlashCommandBuilder()
.setName('warn') .setName('warn')

View File

@ -1,5 +1,6 @@
import Discord from 'discord.js'; import Discord from 'discord.js';
import TClient from '../client'; import TClient from '../client';
import FormatPlayer from '../helpers/FormatPlayer.js';
import {writeFileSync, readFileSync} from 'node:fs'; import {writeFileSync, readFileSync} from 'node:fs';
import {FSPlayer, FSData, FSCareerSavegame, TServer} from '../typings/interfaces'; import {FSPlayer, FSData, FSCareerSavegame, TServer} from '../typings/interfaces';
@ -12,12 +13,6 @@ export default async(client:TClient, Channel:string, Message:string, Server:TSer
const serverErrorEmbed = new client.embed().setColor(client.config.embedColorRed).setTitle('Host did not respond back in time'); const serverErrorEmbed = new client.embed().setColor(client.config.embedColorRed).setTitle('Host did not respond back in time');
const genericEmbed = new client.embed(); const genericEmbed = new client.embed();
const decoPlayer = (player:FSPlayer)=>{
let decorator = player.isAdmin ? ':detective:' : '';
decorator += player.name.includes('Toast') ? '<:toastv2:1132681026662056079>' : '';
return decorator
}
const HITALL = async()=>{ const HITALL = async()=>{
let sessionInit = {signal: AbortSignal.timeout(8200),headers:{'User-Agent':`Daggerbot - HITALL/undici`}}; let sessionInit = {signal: AbortSignal.timeout(8200),headers:{'User-Agent':`Daggerbot - HITALL/undici`}};
try { try {
@ -42,17 +37,17 @@ export default async(client:TClient, Channel:string, Message:string, Server:TSer
// Join/Leave log // Join/Leave log
function playerLogEmbed(player:FSPlayer,joinLog:boolean){ function playerLogEmbed(player:FSPlayer,joinLog:boolean){
const logEmbed = new client.embed().setDescription(`**${player.name}${decoPlayer(player)}** ${joinLog ? 'joined' : 'left'} **${client.MPServerCache[ServerName].name}** at <t:${Math.round(Date.now()/1000)}:t>`); const logEmbed = new client.embed().setDescription(`**${player.name}${FormatPlayer.decoratePlayerIcons(player)}** ${joinLog ? 'joined' : 'left'} **${client.MPServerCache[ServerName].name}** at <t:${Math.round(Date.now()/1000)}:t>`);
if (joinLog) return logEmbed.setColor(client.config.embedColorGreen); if (joinLog) return logEmbed.setColor(client.config.embedColorGreen);
else if (player.uptime > 0) return logEmbed.setColor(client.config.embedColorRed).setFooter({text:`Farmed for ${client.formatPlayerUptime(player.uptime)}`}); else if (player.uptime > 0) return logEmbed.setColor(client.config.embedColorRed).setFooter({text:`Farmed for ${FormatPlayer.uptimeFormat(player.uptime)}`});
else return logEmbed.setColor(client.config.embedColorRed); else return logEmbed.setColor(client.config.embedColorRed);
} }
const serverLog = client.channels.resolve(client.config.mainServer.channels.fs_server_log) as Discord.TextChannel; const serverLog = client.channels.resolve(client.config.mainServer.channels.fs_server_log) as Discord.TextChannel;
const playersOnServer = hitDSS.slots?.players.filter(x=>x.isUsed); const playersOnServer = hitDSS.slots?.players.filter(x=>x.isUsed);
const playersInCache = client.MPServerCache[ServerName].players; const playersInCache = client.MPServerCache[ServerName].players;
if (!playersOnServer ?? playersOnServer === undefined) return new Error('[MPLoop] Empty array, ignoring...'); // For the love of god, stop throwing errors everytime. if (!playersOnServer ?? playersOnServer === undefined) return console.log('[MPLoop] Empty array, ignoring...'); // For the love of god, stop throwing errors everytime.
playersOnServer.forEach(player=>playerData.push(`**${player.name}${decoPlayer(player)}**\nFarming for ${client.formatPlayerUptime(player.uptime)}`)); playersOnServer.forEach(player=>playerData.push(`**${player.name}${FormatPlayer.decoratePlayerIcons(player)}**\nFarming for ${FormatPlayer.uptimeFormat(player.uptime)}`));
// Player leaving // Player leaving
for (const player of playersInCache.filter(x=>!playersOnServer.some(y=>y.name === x.name))){ for (const player of playersInCache.filter(x=>!playersOnServer.some(y=>y.name === x.name))){

20
src/funcs/Punish.ts Normal file
View File

@ -0,0 +1,20 @@
import Discord from 'discord.js';
import TClient from '../client.js';
export default async(client:TClient, interaction: Discord.ChatInputCommandInteraction<'cached'>, type: string)=>{
if (!client.isStaff(interaction.member as Discord.GuildMember)) return client.youNeedRole(interaction, 'dcmod');
const time = interaction.options.getString('time') ?? undefined;
const reason = interaction.options.getString('reason') ?? 'Reason unspecified';
const GuildMember = interaction.options.getMember('member') ?? undefined;
const User = interaction.options.getUser('member', true);
console.log(client.logTime(), `[PunishmentLog] ${GuildMember?.user?.username ?? User?.username ?? 'No user data'} ${time ? ['warn', 'kick'].includes(type) ? 'and no duration set' : `and ${time} (duration)` : ''} was used in /${interaction.commandName} for ${reason}`);
(client.channels.cache.get(client.config.mainServer.channels.punishment_log) as Discord.TextChannel).send({embeds:[new client.embed().setColor(client.config.embedColor).setAuthor({name: interaction?.user?.username, iconURL: interaction?.user?.displayAvatarURL({size:2048})}).setTitle('Punishment Log').setDescription(`${GuildMember?.user?.username ?? User?.username ?? 'No user data'} ${time ? ['warn', 'kick'].includes(client.punishments.type) ? 'and no duration set' : `and ${time} (duration)` : ''} was used in \`/${interaction.commandName}\` for \`${reason}\``).setTimestamp()]});
if (interaction.user.id === User.id) return interaction.reply(`You cannot ${type} yourself.`);
if (!GuildMember && type != 'unban') return interaction.reply(`You cannot ${type} someone who is not in the server.`);
if (User.bot) return interaction.reply(`You cannot ${type} a bot!`);
await interaction.deferReply();
await client.punishments.addPunishment(type, {time, interaction}, interaction.user.id, reason, User, GuildMember);
}

18
src/funcs/YTLoop.ts Normal file
View File

@ -0,0 +1,18 @@
import {TextChannel} from 'discord.js';
import TClient from '../client.js';
export default async(client: TClient, YTChannelID: string, YTChannelName: string, DiscordChannelID: string, DiscordRoleID: string)=>{
let Data: any;
try {
await fetch(`https://www.youtube.com/feeds/videos.xml?channel_id=${YTChannelID}`, {signal: AbortSignal.timeout(8000), headers: {'User-Agent': 'Daggerbot - Notification/undici'}}).then(async xml=>Data = client.xjs.xml2js(await xml.text(), {compact: true}))
} catch(err){
console.log(client.logTime(), `Failed to fetch "${YTChannelName}" from YouTube`)
}
if (!Data) return;
if (!client.YTCache[YTChannelID]) return client.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text;
if (Data.feed.entry[1]['yt:videoId']._text === client.YTCache[YTChannelID]){
client.YTCache[YTChannelID] = Data.feed.entry[0]['yt:videoId']._text;
(client.channels.resolve(DiscordChannelID) as TextChannel).send({content: `<@&${DiscordRoleID}> (Ping notification are currently WIP, no eta when complete, the mentioned role is a placeholder for now)\n**${YTChannelName}** just uploaded a video!\n${Data.feed.entry[0].link._attributes.href}`, allowedMentions: {parse: ['roles']}})
}
}

View File

@ -0,0 +1,5 @@
export default (bytes:number, decimals:number = 2)=>{
if (bytes === 0) return '0 Bytes';
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return parseFloat((bytes / Math.pow(1024, i)).toFixed(decimals < 0 ? 0 : decimals))+ ' ' +['Bytes', 'KB', 'MB', 'GB', 'TB'][i]
}

View File

@ -0,0 +1,22 @@
import {FSPlayer} from '../typings/interfaces';
export default class FormatPlayer {
static uptimeFormat(playTime: number){
var Hours = 0;
playTime = Math.floor(Number(playTime));
if(playTime >= 60){
var Hours = Math.floor(Number(playTime)/60);
var Minutes = (Number(playTime)-(Hours*60));
} else Minutes = Number(playTime)
if(Hours >= 24){
var Days = Math.floor(Number(Hours)/24);
var Hours = (Hours-(Days*24));
} return (Days > 0 ? Days+' d ':'')+(Hours > 0 ? Hours+' h ':'')+(Minutes > 0 ? Minutes+' m':'')
}
static decoratePlayerIcons(player:FSPlayer){
let decorator = player.isAdmin ? ':detective:' : '';
decorator += player.name.includes('Toast') ? '<:toast:1132681026662056079>' : '';
decorator += player.name.includes('Daggerwin') ? '<:Daggerwin:549283056079339520>' : ''; // Probably useless lol, but we'll see.
return decorator
}
}

35
src/helpers/FormatTime.ts Normal file
View File

@ -0,0 +1,35 @@
interface formatTimeOpt {
longNames: boolean,
commas: boolean
}
export default (integer:number, accuracy:number = 1, options?:formatTimeOpt)=>{
let achievedAccuracy = 0;
let text:any = '';
for (const timeName of [
{name: 'year', length: 31536000000},
{name: 'month', length: 2592000000},
{name: 'week', length: 604800000},
{name: 'day', length: 86400000},
{name: 'hour', length: 3600000},
{name: 'minute', length: 60000},
{name: 'second', length: 1000}
]){
if (achievedAccuracy < accuracy){
const fullTimelengths = Math.floor(integer/timeName.length);
if (fullTimelengths === 0) continue;
achievedAccuracy++;
text += fullTimelengths + (options?.longNames ? (' '+timeName.name+(fullTimelengths === 1 ? '' : 's')) : timeName.name.slice(0, timeName.name === 'month' ? 2 : 1)) + (options?.commas ? ', ' : ' ');
integer -= fullTimelengths*timeName.length;
} else break;
}
if (text.length === 0) text = integer + (options?.longNames ? ' milliseconds' : 'ms') + (options?.commas ? ', ' : '');
if (options?.commas){
text = text.slice(0, -2);
if (options?.longNames){
text = text.split('');
text[text.lastIndexOf(',')] = ' and';
text = text.join('');
}
} return text.trim();
}

View File

@ -0,0 +1,18 @@
export default class UsernameHelper {
static stripName(text: string){
let matchesLeft = true;
const dirSlash = process.platform === 'linux' ? '\/' : '\\';
const array = text.split(dirSlash);
while (matchesLeft) {
let usersIndex = array.indexOf(process.platform === 'linux' ? 'media' : 'Users');
if (usersIndex < 1) matchesLeft = false;
else {
let usernameIndex = usersIndex + 1;
if (array[usernameIndex].length === 0) usernameIndex += 1;
array[usernameIndex] = '・'.repeat(array[usernameIndex].length);
array[usersIndex] = process.platform === 'linux' ? 'med\u200bia' : 'Us\u200bers';
}
return array.join(dirSlash);
}
}
}

View File

@ -2,6 +2,7 @@ import Discord from 'discord.js';
import TClient from './client.js'; import TClient from './client.js';
const client = new TClient; const client = new TClient;
client.init(); client.init();
import YTLoop from './funcs/YTLoop.js';
import MPLoop from './funcs/MPLoop.js'; import MPLoop from './funcs/MPLoop.js';
import {Player} from 'discord-player'; import {Player} from 'discord-player';
const player = Player.singleton(client); const player = Player.singleton(client);
@ -10,11 +11,7 @@ import {writeFileSync, readFileSync} from 'node:fs';
// Error handler // Error handler
function DZ(error:Error, type:string){// Yes, I may have shiternet but I don't need to wake up to like a hundred messages or so. function DZ(error:Error, type:string){// Yes, I may have shiternet but I don't need to wake up to like a hundred messages or so.
if ([ if (JSON.parse(readFileSync('src/errorBlocklist.json', 'utf8')).includes(error.message)) return;// I wonder if my idea works, if not then please run me over with a bulldozer.
'ConnectTimeoutError: Connect Timeout Error', 'getaddrinfo EAI_AGAIN discord.com',
'[Error: 30130000:error:0A000410:SSL', '[Error: F8200000:error:0A000410:SSL',
'HTTPError: Internal Server Error'
].includes(error.message)) return;
console.error(error); console.error(error);
(client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel | null)?.send({embeds: [new client.embed().setColor('#560000').setTitle('Error caught!').setFooter({text: 'Error type: ' + type}).setDescription(`**Error:**\n\`\`\`${error.message}\`\`\`**Stack:**\n\`\`\`${`${error.stack}`.slice(0, 2500)}\`\`\``)]}) (client.channels.resolve(client.config.mainServer.channels.errors) as Discord.TextChannel | null)?.send({embeds: [new client.embed().setColor('#560000').setTitle('Error caught!').setFooter({text: 'Error type: ' + type}).setDescription(`**Error:**\n\`\`\`${error.message}\`\`\`**Stack:**\n\`\`\`${`${error.stack}`.slice(0, 2500)}\`\`\``)]})
} }
@ -41,9 +38,9 @@ if (client.config.botSwitches.mpstats) setInterval(async()=>{
const serverlake = (await client.MPServer._content.findById(client.config.mainServer.id)); const serverlake = (await client.MPServer._content.findById(client.config.mainServer.id));
for await (const [locName, locArea] of Object.entries(client.config.MPStatsLocation)) await MPLoop(client, locArea.channel, locArea.message, serverlake[locName], locName) for await (const [locName, locArea] of Object.entries(client.config.MPStatsLocation)) await MPLoop(client, locArea.channel, locArea.message, serverlake[locName], locName)
}, 35000); }, 35000);
setInterval(async()=>{ setInterval(async()=>{// Ping notification is currently WIP, it might be active in production but I want to see how it goes with role mentions first so I can make any further changes.
client.YTLoop('UCQ8k8yTDLITldfWYKDs3xFg', 'Daggerwin', '528967918772551702'); // 528967918772551702 = #videos-and-streams YTLoop(client, 'UCQ8k8yTDLITldfWYKDs3xFg', 'Daggerwin', '528967918772551702', '1011341005389307925'); // 528967918772551702 = #videos-and-streams; 1011341005389307925 = Bot Tech;
client.YTLoop('UCguI73--UraJpso4NizXNzA', 'Machinery Restorer', '767444045520961567') // 767444045520961567 = #machinery-restorer YTLoop(client, 'UCguI73--UraJpso4NizXNzA', 'Machinery Restorer', '767444045520961567', '989591094524276796') // 767444045520961567 = #machinery-restorer; 989591094524276796 = Temp;
}, 300000) }, 300000)
// Event loop for punishments and daily msgs // Event loop for punishments and daily msgs

View File

@ -2,6 +2,7 @@ import Discord from 'discord.js';
import TClient from '../client.js'; import TClient from '../client.js';
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import ms from 'ms'; import ms from 'ms';
import FormatTime from '../helpers/FormatTime.js';
import {Punishment} from '../typings/interfaces.js'; import {Punishment} from '../typings/interfaces.js';
const Schema = mongoose.model('punishments', new mongoose.Schema({ const Schema = mongoose.model('punishments', new mongoose.Schema({
@ -36,7 +37,7 @@ export default class punishments extends Schema {
{name: '\u200b', value: '\u200b', inline: true}, {name: '\u200b', value: '\u200b', inline: true},
{name: '🔹 Reason', value: `\`${punishment.reason}\``, inline: true}) {name: '🔹 Reason', value: `\`${punishment.reason}\``, inline: true})
.setColor(this.client.config.embedColor).setTimestamp(punishment.time) .setColor(this.client.config.embedColor).setTimestamp(punishment.time)
if (punishment.duration) embed.addFields({name: '🔹 Duration', value: this.client.formatTime(punishment.duration, 100), inline: true}, {name: '\u200b', value: '\u200b', inline: true}) if (punishment.duration) embed.addFields({name: '🔹 Duration', value: `${FormatTime(punishment.duration, 100)}`, inline: true}, {name: '\u200b', value: '\u200b', inline: true})
if (punishment.cancels) { if (punishment.cancels) {
const cancels = await this._content.findById(punishment.cancels); const cancels = await this._content.findById(punishment.cancels);
embed.addFields({name: '🔹 Overwrites', value: `This case overwrites Case #${cancels.id}\n\`${cancels.reason}\``}) embed.addFields({name: '🔹 Overwrites', value: `This case overwrites Case #${cancels.id}\n\`${cancels.reason}\``})
@ -72,7 +73,7 @@ export default class punishments extends Schema {
if (type == 'mute') timeInMillis = time ? ms(time) : 2419140000; // Timeouts have a limit of 4 weeks if (type == 'mute') timeInMillis = time ? ms(time) : 2419140000; // Timeouts have a limit of 4 weeks
else timeInMillis = time ? ms(time) : null; else timeInMillis = time ? ms(time) : null;
const durationText = timeInMillis ? ` for ${this.client.formatTime(timeInMillis, 4, {longNames:true,commas:true})}` : ''; const durationText = timeInMillis ? ` for ${FormatTime(timeInMillis, 4, {longNames:true,commas:true})}` : '';
if (time) embed.addFields({name: 'Duration', value: durationText}); if (time) embed.addFields({name: 'Duration', value: durationText});
if (GuildMember){ if (GuildMember){

View File

@ -4,10 +4,6 @@ export interface UserLevels {
messages: number, messages: number,
level: number level: number
} }
export interface formatTimeOpt {
longNames: boolean,
commas: boolean
}
export interface punOpt { export interface punOpt {
time?: string, time?: string,
reason?: string, reason?: string,