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

Compare commits

...

3 Commits

Author SHA1 Message Date
AnxietyisReal
e3f0da75b3 Update packages 2023-08-30 18:38:48 +10:00
AnxietyisReal
793c22dbcd Move essentials out of client.ts 2023-08-30 18:34:59 +10:00
AnxietyisReal
de7169035f Rename dontlookatme to spotify 2023-08-30 16:42:06 +10:00
25 changed files with 238 additions and 224 deletions

56
.pnp.cjs generated
View File

@ -39,10 +39,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["discord.js", "npm:14.13.0"],\ ["discord.js", "npm:14.13.0"],\
["libsodium-wrappers", "npm:0.7.11"],\ ["libsodium-wrappers", "npm:0.7.11"],\
["moment", "npm:2.29.4"],\ ["moment", "npm:2.29.4"],\
["mongoose", "npm:7.4.5"],\ ["mongoose", "npm:7.5.0"],\
["ms", "npm:2.1.3"],\ ["ms", "npm:2.1.3"],\
["prism-media", "virtual:20c353e2d6536e37339997f03975c6a660f4d296e664d291bd43620c6162cca8eb5ef90b0998dc9db75ff6862e5da587d0530bae26805f5fadc8f17aaa4ff794#npm:1.3.5"],\ ["prism-media", "virtual:20c353e2d6536e37339997f03975c6a660f4d296e664d291bd43620c6162cca8eb5ef90b0998dc9db75ff6862e5da587d0530bae26805f5fadc8f17aaa4ff794#npm:1.3.5"],\
["systeminformation", "npm:5.21.0"],\ ["systeminformation", "npm:5.21.1"],\
["typescript", "patch:typescript@npm%3A5.2.2#~builtin<compat/typescript>::version=5.2.2&hash=f3b441"],\ ["typescript", "patch:typescript@npm%3A5.2.2#~builtin<compat/typescript>::version=5.2.2&hash=f3b441"],\
["xml-js", "npm:1.6.11"],\ ["xml-js", "npm:1.6.11"],\
["youtube-sr", "npm:4.3.4"],\ ["youtube-sr", "npm:4.3.4"],\
@ -268,6 +268,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
]],\ ]],\
["@mongodb-js/saslprep", [\
["npm:1.1.0", {\
"packageLocation": "./.yarn/cache/@mongodb-js-saslprep-npm-1.1.0-3906c025b8-1479a43e21.zip/node_modules/@mongodb-js/saslprep/",\
"packageDependencies": [\
["@mongodb-js/saslprep", "npm:1.1.0"],\
["sparse-bitfield", "npm:3.0.3"]\
],\
"linkType": "HARD"\
}]\
]],\
["@npmcli/fs", [\ ["@npmcli/fs", [\
["npm:3.1.0", {\ ["npm:3.1.0", {\
"packageLocation": "./.yarn/cache/@npmcli-fs-npm-3.1.0-0844a57978-a50a6818de.zip/node_modules/@npmcli/fs/",\ "packageLocation": "./.yarn/cache/@npmcli-fs-npm-3.1.0-0844a57978-a50a6818de.zip/node_modules/@npmcli/fs/",\
@ -922,10 +932,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["discord.js", "npm:14.13.0"],\ ["discord.js", "npm:14.13.0"],\
["libsodium-wrappers", "npm:0.7.11"],\ ["libsodium-wrappers", "npm:0.7.11"],\
["moment", "npm:2.29.4"],\ ["moment", "npm:2.29.4"],\
["mongoose", "npm:7.4.5"],\ ["mongoose", "npm:7.5.0"],\
["ms", "npm:2.1.3"],\ ["ms", "npm:2.1.3"],\
["prism-media", "virtual:20c353e2d6536e37339997f03975c6a660f4d296e664d291bd43620c6162cca8eb5ef90b0998dc9db75ff6862e5da587d0530bae26805f5fadc8f17aaa4ff794#npm:1.3.5"],\ ["prism-media", "virtual:20c353e2d6536e37339997f03975c6a660f4d296e664d291bd43620c6162cca8eb5ef90b0998dc9db75ff6862e5da587d0530bae26805f5fadc8f17aaa4ff794#npm:1.3.5"],\
["systeminformation", "npm:5.21.0"],\ ["systeminformation", "npm:5.21.1"],\
["typescript", "patch:typescript@npm%3A5.2.2#~builtin<compat/typescript>::version=5.2.2&hash=f3b441"],\ ["typescript", "patch:typescript@npm%3A5.2.2#~builtin<compat/typescript>::version=5.2.2&hash=f3b441"],\
["xml-js", "npm:1.6.11"],\ ["xml-js", "npm:1.6.11"],\
["youtube-sr", "npm:4.3.4"],\ ["youtube-sr", "npm:4.3.4"],\
@ -1842,18 +1852,19 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["mongodb", [\ ["mongodb", [\
["npm:5.7.0", {\ ["npm:5.8.1", {\
"packageLocation": "./.yarn/cache/mongodb-npm-5.7.0-c5e415a2e7-16357b6229.zip/node_modules/mongodb/",\ "packageLocation": "./.yarn/cache/mongodb-npm-5.8.1-d655990b24-da8fc05952.zip/node_modules/mongodb/",\
"packageDependencies": [\ "packageDependencies": [\
["mongodb", "npm:5.7.0"]\ ["mongodb", "npm:5.8.1"]\
],\ ],\
"linkType": "SOFT"\ "linkType": "SOFT"\
}],\ }],\
["virtual:f13f0698828b1136b9c2fe7fd47b1d970be7543f740ea5a6542d5de086caf8ce3fde9627ee2446a16f34f568a86debbe37012d1a655c3979e155ff37d7833a12#npm:5.7.0", {\ ["virtual:dd2c4ef6f94e58af1d1910a9e458d5ca3cd2a693365aac2a33b0318c1be1170eb680a561461dbf9dbd8568b885dbf5005ce2287e0fee26acec16b0e35305f4e2#npm:5.8.1", {\
"packageLocation": "./.yarn/__virtual__/mongodb-virtual-66143c0721/0/cache/mongodb-npm-5.7.0-c5e415a2e7-16357b6229.zip/node_modules/mongodb/",\ "packageLocation": "./.yarn/__virtual__/mongodb-virtual-2b368f364a/0/cache/mongodb-npm-5.8.1-d655990b24-da8fc05952.zip/node_modules/mongodb/",\
"packageDependencies": [\ "packageDependencies": [\
["mongodb", "virtual:f13f0698828b1136b9c2fe7fd47b1d970be7543f740ea5a6542d5de086caf8ce3fde9627ee2446a16f34f568a86debbe37012d1a655c3979e155ff37d7833a12#npm:5.7.0"],\ ["mongodb", "virtual:dd2c4ef6f94e58af1d1910a9e458d5ca3cd2a693365aac2a33b0318c1be1170eb680a561461dbf9dbd8568b885dbf5005ce2287e0fee26acec16b0e35305f4e2#npm:5.8.1"],\
["@aws-sdk/credential-providers", null],\ ["@aws-sdk/credential-providers", null],\
["@mongodb-js/saslprep", "npm:1.1.0"],\
["@mongodb-js/zstd", null],\ ["@mongodb-js/zstd", null],\
["@types/aws-sdk__credential-providers", null],\ ["@types/aws-sdk__credential-providers", null],\
["@types/kerberos", null],\ ["@types/kerberos", null],\
@ -1864,7 +1875,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["kerberos", null],\ ["kerberos", null],\
["mongodb-client-encryption", null],\ ["mongodb-client-encryption", null],\
["mongodb-connection-string-url", "npm:2.6.0"],\ ["mongodb-connection-string-url", "npm:2.6.0"],\
["saslprep", "npm:1.0.3"],\
["snappy", null],\ ["snappy", null],\
["socks", "npm:2.7.1"]\ ["socks", "npm:2.7.1"]\
],\ ],\
@ -1895,13 +1905,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["mongoose", [\ ["mongoose", [\
["npm:7.4.5", {\ ["npm:7.5.0", {\
"packageLocation": "./.yarn/cache/mongoose-npm-7.4.5-f13f069882-a017bd90bb.zip/node_modules/mongoose/",\ "packageLocation": "./.yarn/cache/mongoose-npm-7.5.0-dd2c4ef6f9-3e4219fd29.zip/node_modules/mongoose/",\
"packageDependencies": [\ "packageDependencies": [\
["mongoose", "npm:7.4.5"],\ ["mongoose", "npm:7.5.0"],\
["bson", "npm:5.4.0"],\ ["bson", "npm:5.4.0"],\
["kareem", "npm:2.5.1"],\ ["kareem", "npm:2.5.1"],\
["mongodb", "virtual:f13f0698828b1136b9c2fe7fd47b1d970be7543f740ea5a6542d5de086caf8ce3fde9627ee2446a16f34f568a86debbe37012d1a655c3979e155ff37d7833a12#npm:5.7.0"],\ ["mongodb", "virtual:dd2c4ef6f94e58af1d1910a9e458d5ca3cd2a693365aac2a33b0318c1be1170eb680a561461dbf9dbd8568b885dbf5005ce2287e0fee26acec16b0e35305f4e2#npm:5.8.1"],\
["mpath", "npm:0.9.0"],\ ["mpath", "npm:0.9.0"],\
["mquery", "npm:5.0.0"],\ ["mquery", "npm:5.0.0"],\
["ms", "npm:2.1.3"],\ ["ms", "npm:2.1.3"],\
@ -2335,16 +2345,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\
]],\ ]],\
["saslprep", [\
["npm:1.0.3", {\
"packageLocation": "./.yarn/cache/saslprep-npm-1.0.3-8db649c346-4fdc0b70fb.zip/node_modules/saslprep/",\
"packageDependencies": [\
["saslprep", "npm:1.0.3"],\
["sparse-bitfield", "npm:3.0.3"]\
],\
"linkType": "HARD"\
}]\
]],\
["sax", [\ ["sax", [\
["npm:1.2.4", {\ ["npm:1.2.4", {\
"packageLocation": "./.yarn/cache/sax-npm-1.2.4-178f05f12f-d3df7d32b8.zip/node_modules/sax/",\ "packageLocation": "./.yarn/cache/sax-npm-1.2.4-178f05f12f-d3df7d32b8.zip/node_modules/sax/",\
@ -2598,10 +2598,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\ }]\
]],\ ]],\
["systeminformation", [\ ["systeminformation", [\
["npm:5.21.0", {\ ["npm:5.21.1", {\
"packageLocation": "./.yarn/unplugged/systeminformation-npm-5.21.0-553db82075/node_modules/systeminformation/",\ "packageLocation": "./.yarn/unplugged/systeminformation-npm-5.21.1-9b1e539abd/node_modules/systeminformation/",\
"packageDependencies": [\ "packageDependencies": [\
["systeminformation", "npm:5.21.0"]\ ["systeminformation", "npm:5.21.1"]\
],\ ],\
"linkType": "HARD"\ "linkType": "HARD"\
}]\ }]\

View File

@ -37,10 +37,10 @@
"discord.js": "14.13.0", "discord.js": "14.13.0",
"libsodium-wrappers": "0.7.11", "libsodium-wrappers": "0.7.11",
"moment": "2.29.4", "moment": "2.29.4",
"mongoose": "7.4.5", "mongoose": "7.5.0",
"ms": "2.1.3", "ms": "2.1.3",
"prism-media": "1.3.5", "prism-media": "1.3.5",
"systeminformation": "5.21.0", "systeminformation": "5.21.1",
"typescript": "5.2.2", "typescript": "5.2.2",
"xml-js": "1.6.11", "xml-js": "1.6.11",
"youtube-sr": "4.3.4", "youtube-sr": "4.3.4",

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}});
}); });
}); });
} }
@ -35,12 +37,12 @@ export default {
if (typeof output === 'object') output = 'js\n'+util.formatWithOptions({depth: 1}, '%O', output) if (typeof output === 'object') output = 'js\n'+util.formatWithOptions({depth: 1}, '%O', output)
else output = '\n' + String(output); else output = '\n' + String(output);
[ [
client.tokens.main,client.tokens.beta,client.tokens.toast,client.tokens.dontlookatme.client,client.tokens.dontlookatme.secret, client.tokens.main,client.tokens.beta,client.tokens.toast,client.tokens.spotify.client,client.tokens.spotify.secret,
client.tokens.mongodb_uri,client.tokens.mongodb_uri_dev,client.tokens.octokit client.tokens.mongodb_uri,client.tokens.mongodb_uri_dev,client.tokens.octokit
].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

@ -7,7 +7,7 @@ export default {
if (!client.config.botSwitches.music && !client.config.whitelist.includes(interaction.user.id)) return interaction.reply({content:'Music module is currently disabled.',ephemeral:true}); if (!client.config.botSwitches.music && !client.config.whitelist.includes(interaction.user.id)) return interaction.reply({content:'Music module is currently disabled.',ephemeral:true});
if (!client.isStaff(interaction.member) && !client.config.whitelist.includes(interaction.member.id)) return interaction.reply('Music module is close to being completed, some parts may be incomplete or broken, so it has been restricted to staff for time-being.'); if (!client.isStaff(interaction.member) && !client.config.whitelist.includes(interaction.member.id)) return interaction.reply('Music module is close to being completed, some parts may be incomplete or broken, so it has been restricted to staff for time-being.');
const player = Player.singleton(client); const player = Player.singleton(client);
await player.extractors.register(SpotifyExtractor,{clientId: client.tokens.dontlookatme.client, clientSecret: client.tokens.dontlookatme.secret}); await player.extractors.register(SpotifyExtractor,{clientId: client.tokens.spotify.client, clientSecret: client.tokens.spotify.secret});
if (!interaction.member.voice.channel) return interaction.reply('Please join a voice channel first to use the command.'); if (!interaction.member.voice.channel) return interaction.reply('Please join a voice channel first to use the command.');
player.nodes.create(interaction.guildId, { player.nodes.create(interaction.guildId, {
metadata: { metadata: {

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,
@ -116,7 +112,7 @@ export interface Tokens {
main: string main: string
beta: string beta: string
toast: string toast: string
dontlookatme: { spotify: {
client: string, client: string,
secret: string secret: string
} }

View File

@ -198,6 +198,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@mongodb-js/saslprep@npm:^1.1.0":
version: 1.1.0
resolution: "@mongodb-js/saslprep@npm:1.1.0"
dependencies:
sparse-bitfield: ^3.0.3
checksum: 1479a43e216734672f8eb1a2a55165b6896841bd00fb5bd645390a24374ef6c29f0f6d19a43618a19b8f1912fcbd2b2cc2210a62361103d1f28dce6852cf31d4
languageName: node
linkType: hard
"@npmcli/fs@npm:^3.1.0": "@npmcli/fs@npm:^3.1.0":
version: 3.1.0 version: 3.1.0
resolution: "@npmcli/fs@npm:3.1.0" resolution: "@npmcli/fs@npm:3.1.0"
@ -743,10 +752,10 @@ __metadata:
discord.js: 14.13.0 discord.js: 14.13.0
libsodium-wrappers: 0.7.11 libsodium-wrappers: 0.7.11
moment: 2.29.4 moment: 2.29.4
mongoose: 7.4.5 mongoose: 7.5.0
ms: 2.1.3 ms: 2.1.3
prism-media: 1.3.5 prism-media: 1.3.5
systeminformation: 5.21.0 systeminformation: 5.21.1
typescript: 5.2.2 typescript: 5.2.2
xml-js: 1.6.11 xml-js: 1.6.11
youtube-sr: 4.3.4 youtube-sr: 4.3.4
@ -1545,22 +1554,22 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"mongodb@npm:5.7.0": "mongodb@npm:5.8.1":
version: 5.7.0 version: 5.8.1
resolution: "mongodb@npm:5.7.0" resolution: "mongodb@npm:5.8.1"
dependencies: dependencies:
"@mongodb-js/saslprep": ^1.1.0
bson: ^5.4.0 bson: ^5.4.0
mongodb-connection-string-url: ^2.6.0 mongodb-connection-string-url: ^2.6.0
saslprep: ^1.0.3
socks: ^2.7.1 socks: ^2.7.1
peerDependencies: peerDependencies:
"@aws-sdk/credential-providers": ^3.201.0 "@aws-sdk/credential-providers": ^3.188.0
"@mongodb-js/zstd": ^1.1.0 "@mongodb-js/zstd": ^1.0.0
kerberos: ^2.0.1 kerberos: ^1.0.0 || ^2.0.0
mongodb-client-encryption: ">=2.3.0 <3" mongodb-client-encryption: ">=2.3.0 <3"
snappy: ^7.2.2 snappy: ^7.2.2
dependenciesMeta: dependenciesMeta:
saslprep: "@mongodb-js/saslprep":
optional: true optional: true
peerDependenciesMeta: peerDependenciesMeta:
"@aws-sdk/credential-providers": "@aws-sdk/credential-providers":
@ -1573,22 +1582,22 @@ __metadata:
optional: true optional: true
snappy: snappy:
optional: true optional: true
checksum: 16357b6229abac165aecea15a6efa873ec8662a00411ecb9e49853f05a590be31aab63d404486125778eedaafe76d70e84eea682fa89b138decc247f4870d2ec checksum: da8fc05952266f9b636000d74e6c8889306fc287922651526029a61ede3c75f793edb504a02c1f64fec9fea9aa17323bf95eb4902776778a1def5eba07b32b72
languageName: node languageName: node
linkType: hard linkType: hard
"mongoose@npm:7.4.5": "mongoose@npm:7.5.0":
version: 7.4.5 version: 7.5.0
resolution: "mongoose@npm:7.4.5" resolution: "mongoose@npm:7.5.0"
dependencies: dependencies:
bson: ^5.4.0 bson: ^5.4.0
kareem: 2.5.1 kareem: 2.5.1
mongodb: 5.7.0 mongodb: 5.8.1
mpath: 0.9.0 mpath: 0.9.0
mquery: 5.0.0 mquery: 5.0.0
ms: 2.1.3 ms: 2.1.3
sift: 16.0.1 sift: 16.0.1
checksum: a017bd90bbdf64bf2867abfb0ba5fe84049bf09f8bca53af465a3ad694abd9475c1140041910af8ac86b1185d00ec02fd4c936ffc05b9f67ba8c4b9b246a7a7e checksum: 3e4219fd29a44efe9d1fe41134bdbafca9b44f6da58fc01be3723379954d9ca6bdd8d2bdd352ded932432b9d0e0c5146490add84eb14f4aee3743d94e6cae643
languageName: node languageName: node
linkType: hard linkType: hard
@ -1939,15 +1948,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"saslprep@npm:^1.0.3":
version: 1.0.3
resolution: "saslprep@npm:1.0.3"
dependencies:
sparse-bitfield: ^3.0.3
checksum: 4fdc0b70fb5e523f977de405e12cca111f1f10dd68a0cfae0ca52c1a7919a94d1556598ba2d35f447655c3b32879846c77f9274c90806f6673248ae3cea6ee43
languageName: node
linkType: hard
"sax@npm:^1.1.3, sax@npm:^1.2.4": "sax@npm:^1.1.3, sax@npm:^1.2.4":
version: 1.2.4 version: 1.2.4
resolution: "sax@npm:1.2.4" resolution: "sax@npm:1.2.4"
@ -2175,12 +2175,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"systeminformation@npm:5.21.0": "systeminformation@npm:5.21.1":
version: 5.21.0 version: 5.21.1
resolution: "systeminformation@npm:5.21.0" resolution: "systeminformation@npm:5.21.1"
bin: bin:
systeminformation: lib/cli.js systeminformation: lib/cli.js
checksum: 0d6f22ed92c6e92167a27af5dcc5f1a9c0b2b82a33f9e674f9b2a6c1ebb79141ba405b8bde8e624101766c5d7ef087f50c45411d00690513e38f77e654f468cf checksum: e08e56ea3bf0efc54c7bc0d2a675c4c181d7413d0b26fc80590433f24957e7e3c28fa35c46fae6c066bde4b73d9fccc6305c3b02616b35117df297356f793aa0
conditions: (os=darwin | os=linux | os=win32 | os=freebsd | os=openbsd | os=netbsd | os=sunos | os=android) conditions: (os=darwin | os=linux | os=win32 | os=freebsd | os=openbsd | os=netbsd | os=sunos | os=android)
languageName: node languageName: node
linkType: hard linkType: hard