Skip to content

Commit c5bfb80

Browse files
committed
feat(syncing): allow syncing from mee6
1 parent e8815e5 commit c5bfb80

File tree

3 files changed

+106
-24
lines changed

3 files changed

+106
-24
lines changed

api/index.ts

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => {
195195
} catch (err) {
196196
return res.status(500).json({ message: "Internal server error", err });
197197
}
198-
case 'set':
198+
case 'set':
199199
if (!extraData || typeof extraData.channelId === "undefined") {
200200
return res.status(400).json({ message: "Illegal request" });
201201
}
@@ -297,7 +297,7 @@ app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => {
297297
return res.status(400).json({ message: "Illegal request" });
298298
}
299299

300-
if(!extraData || !extraData.user || !extraData.value) {
300+
if (!extraData || !extraData.user || !extraData.value) {
301301
return res.status(400).json({ message: "Illegal request" });
302302
}
303303

@@ -329,16 +329,16 @@ app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => {
329329
}
330330
}
331331
case "sync": {
332-
if(target !== "polaris") {
332+
if (target !== "polaris" && target !== "mee6") {
333333
return res.status(400).json({ message: "Illegal request" });
334334
}
335-
336-
switch(target) {
335+
336+
switch (target) {
337337
case "polaris": {
338338
try {
339339
const [err, success] = await syncFromPolaris(guild);
340340
if (err) {
341-
if(err instanceof Error && err.message === "Server not found in Polaris") {
341+
if (err instanceof Error && err.message === "Server not found in Polaris") {
342342
return res.status(404).json({ message: "Server not found in Polaris" });
343343
}
344344
return res.status(500).json({ message: "Internal server error", err });
@@ -349,6 +349,21 @@ app.post("/admin/:action/:guild/:target", authMiddleware, async (req, res) => {
349349
return res.status(500).json({ message: "Internal server error", err });
350350
}
351351
}
352+
case "mee6": {
353+
try {
354+
const [err, success] = await syncFromMee6(guild);
355+
if (err) {
356+
if (err instanceof Error && err.message === "Server not found in MEE6") {
357+
return res.status(404).json({ message: "Server not found in MEE6" });
358+
}
359+
return res.status(500).json({ message: "Internal server error", err });
360+
} else {
361+
return res.status(200).json(success);
362+
}
363+
} catch (err) {
364+
return res.status(500).json({ message: "Internal server error", err });
365+
}
366+
}
352367
default:
353368
return res.status(500).json({ message: "Internal server error" });
354369
}
@@ -464,22 +479,22 @@ async function adminRolesAdd(guild: string, role: string, level: number) {
464479
async function syncFromPolaris(guild: string) {
465480
const res = await fetch(`https://gdcolon.com/polaris/api/leaderboard/${guild}`);
466481
const data = await res.json();
467-
if(data.apiError && data.code === "invalidServer") {
482+
if (data.apiError && data.code === "invalidServer") {
468483
return [new Error("Server not found in Polaris"), false];
469484
}
470485
const users = data.leaderboard;
471-
for(let i = 1; i < data.pageInfo.pageCount; i++) {
486+
for (let i = 1; i < data.pageInfo.pageCount; i++) {
472487
const res = await fetch(`https://gdcolon.com/polaris/api/leaderboard/${guild}?page=${i + 1}`);
473488
const data = await res.json();
474489
users.push(...data.leaderboard);
475490
}
476491

477-
if(users.length === 0) {
492+
if (users.length === 0) {
478493
return [new Error("No users found"), false];
479494
}
480495

481496
try {
482-
for(const user of users) {
497+
for (const user of users) {
483498
const xpValue = user.xp;
484499
const level = Math.floor(Math.sqrt(xpValue / 100));
485500
const nextLevel = level + 1;
@@ -520,4 +535,66 @@ async function syncFromPolaris(guild: string) {
520535
}
521536

522537
}
538+
539+
async function syncFromMee6(guild: string) {
540+
const res = await fetch(`https://mee6.xyz/api/plugins/levels/leaderboard/${guild}?limit=1000&page=0`);
541+
const data = await res.json();
542+
if (data.status_code === 404) {
543+
return [new Error("Server not found in MEE6"), false];
544+
}
545+
const users = data.players;
546+
let pageNumber = 1;
547+
while (true) {
548+
const res = await fetch(`https://mee6.xyz/api/plugins/levels/leaderboard/${guild}?limit=1000&page=${pageNumber}`);
549+
const data = await res.json();
550+
users.push(...data.players);
551+
if (data.players.length < 1000) break;
552+
pageNumber += 1;
553+
}
554+
555+
if (users.length === 0) {
556+
return [new Error("No users found"), false];
557+
}
558+
559+
try {
560+
for (const user of users) {
561+
const xpValue = user.xp;
562+
const level = Math.floor(Math.sqrt(xpValue / 100));
563+
const nextLevel = level + 1;
564+
const nextLevelXp = Math.pow(nextLevel, 2) * 100;
565+
const xpNeededForNextLevel = nextLevelXp - xpValue;
566+
const currentLevelXp = Math.pow(level, 2) * 100;
567+
const progressToNextLevel =
568+
((xpValue - currentLevelXp) / (nextLevelXp - currentLevelXp)) * 100;
569+
570+
await new Promise((resolve, reject) => {
571+
pool.query(
572+
`INSERT INTO users (id, guild_id, xp, pfp, name, nickname, level, xp_needed_next_level, progress_next_level) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
573+
[
574+
user.id,
575+
guild,
576+
xpValue,
577+
`https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.webp`,
578+
user.username,
579+
user.username,
580+
level,
581+
xpNeededForNextLevel,
582+
progressToNextLevel.toFixed(2),
583+
],
584+
(err) => {
585+
if (err) {
586+
console.error("Error syncing from MEE6:", err);
587+
reject(err);
588+
} else {
589+
resolve(null);
590+
}
591+
},
592+
);
593+
});
594+
}
595+
return [null, true]
596+
} catch (err) {
597+
return [err, false];
598+
}
599+
}
523600
//#endregion

bot/commands.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import client from '.';
44
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, type CommandInteraction, ChannelType, type APIApplicationCommandOption, GuildMember, AttachmentBuilder, ComponentType } from 'discord.js';
55
import { heapStats } from 'bun:jsc';
6-
import { getGuildLeaderboard, makeGETRequest, getRoles, removeRole, addRole, enableUpdates, disableUpdates, getCooldown, setCooldown, getUpdatesChannel, setUpdatesChannel, setXP, setLevel, syncFromPolaris } from './utils/requestAPI';
6+
import { getGuildLeaderboard, makeGETRequest, getRoles, removeRole, addRole, enableUpdates, disableUpdates, getCooldown, setCooldown, getUpdatesChannel, setUpdatesChannel, setXP, setLevel, syncFromBot } from './utils/requestAPI';
77
import convertToLevels from './utils/convertToLevels';
88
import quickEmbed from './utils/quickEmbed';
99
import { Font, RankCardBuilder } from 'canvacord';
@@ -734,6 +734,10 @@ const commands: Record<string, Command> = {
734734
name: 'Polaris',
735735
value: 'polaris',
736736
},
737+
{
738+
name: 'MEE6',
739+
value: 'mee6',
740+
}
737741
]
738742
}],
739743
name: 'sync',
@@ -757,18 +761,19 @@ const commands: Record<string, Command> = {
757761
}
758762

759763
const bot = interaction.options.get('bot')?.value;
760-
761-
let apiSuccess;
762-
switch (bot) {
763-
case 'polaris':
764-
apiSuccess = await syncFromPolaris(interaction.guildId as string);
765-
if (!apiSuccess) {
766-
await interaction.reply({ ephemeral: true, content: 'Error syncing data! This might mean that Polaris is not set up for this server, or the leaderboard for this server is not public.' });
767-
return;
768-
}
769-
await interaction.reply({ ephemeral: true, content: 'Data synced!' });
770-
return;
764+
const formattedBotNames = {
765+
'polaris': 'Polaris',
766+
'mee6': 'MEE6'
767+
};
768+
769+
await interaction.reply({ ephemeral: true, content: `Syncing data from ${formattedBotNames[bot as keyof typeof formattedBotNames]}...` });
770+
const apiSuccess = await syncFromBot(interaction.guildId as string, bot as string);
771+
if (!apiSuccess) {
772+
await interaction.editReply({ content: `Error syncing data! This might mean that ${formattedBotNames[bot as keyof typeof formattedBotNames]} is not set up for this server, or the leaderboard for this server is not public.` });
773+
return;
771774
}
775+
await interaction.editReply({ content: 'Data synced!' });
776+
return;
772777
}
773778
}
774779
};

bot/utils/requestAPI.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,8 @@ export async function setCooldown(guild: string, cooldown: number) {
207207
//#endregion
208208

209209
//#region Sync
210-
export async function syncFromPolaris(guild: string) {
211-
const response = await fetch(`http://localhost:18103/admin/sync/${guild}/polaris`, {
210+
export async function syncFromBot(guild: string, bot: string) {
211+
const response = await fetch(`http://localhost:18103/admin/sync/${guild}/${bot}`, {
212212
"headers": {
213213
'Content-Type': 'application/json',
214214
'Authorization': process.env.AUTH as string,

0 commit comments

Comments
 (0)