| import { ChannelType, Client, Collection, Guild, GuildEmoji, GuildInvitableChannelResolvable, IntentsBitField } from 'discord.js'; |
| import { writeFileSync, readdirSync, readFileSync } from 'fs' |
| import Canvas from 'canvas'; |
| import GIFEncoder from 'gifencoder'; |
| import Sharp from 'sharp'; |
| |
| async function staticToAnimatedEmoji(imagePath: string): Promise<Buffer> { |
| const image = Sharp(imagePath); |
| const metadata = await image.metadata(); |
| const data = await image.raw().toBuffer(); |
| if (!metadata.height || !metadata.width) throw new Error(`${imagePath} has no height or width`); |
| const encoder = new GIFEncoder(metadata.width, metadata.height); |
| encoder.setRepeat(0); |
| encoder.start(); |
| |
| const canvas = Canvas.createCanvas(metadata.width, metadata.height); |
| const ctx = canvas.getContext('2d'); |
| const imageData = new Canvas.ImageData( |
| new Uint8ClampedArray(data), |
| canvas.width, |
| canvas.height |
| ); |
| |
| ctx.putImageData(imageData, 0, 0); |
| |
| encoder.addFrame(ctx); |
| encoder.addFrame(ctx); |
| |
| encoder.finish(); |
| |
| let finished = encoder.out.getData(); |
| |
| return finished; |
| } |
| |
| async function uploadEmoji(guild: Guild, toUpload: {name: string, attachment: Buffer}): Promise<GuildEmoji> { |
| const emoji = await guild.emojis.create(toUpload) |
| |
| return emoji; |
| } |
| |
| async function propogateGuilds(client: Client<true>): Promise<Collection<string, Guild>> { |
| console.log("Fetching Guilds") |
| await client.guilds.fetch(); |
| let guilds = client.guilds.cache.filter((guild) => guild.ownerId == client.user.id); |
| |
| if (guilds.size < 10) { |
| console.log(`Creating ${client.user.username} Emoji ${guilds.size + 1}`) |
| const created = await client.guilds.create({ |
| name: `${client.user.username} Emoji ${guilds.size + 1}` |
| }); |
| console.log(`Created: ${created.name}: ${created.id}`) |
| return await propogateGuilds(client); |
| } |
| |
| return guilds; |
| } |
| |
| const client = new Client({ |
| intents: [ |
| IntentsBitField.Flags.GuildEmojisAndStickers, |
| IntentsBitField.Flags.Guilds |
| ] |
| }); |
| |
| client.on('warn', (m) => console.warn(m)); |
| client.on('error', (m) => console.error(m.message)); |
| client.rest.on("rateLimited", rateLimitData => { |
| console.table({ |
| Global: rateLimitData.global, |
| Endpoint: rateLimitData.route, |
| Limit: rateLimitData.limit, |
| TimeToRetry: `${Math.floor((rateLimitData.retryAfter / 1000) / 60)}M ${Math.floor((rateLimitData.retryAfter / 1000) % 60)}S` |
| }); |
| }); |
| |
| client.once('ready', async (client) => { |
| if (!process.env.EMOJI_DIR) throw new Error("Missing Emoji Directory"); |
| console.log('ready') |
| let emojis: Collection<string, string> = new Collection(); |
| const dir = readdirSync(process.env.EMOJI_DIR, { |
| withFileTypes: true |
| }).filter(file => file.isFile()); |
| console.log(dir) |
| const emojiFiles = dir.filter(file => file.name.endsWith('.png')); |
| |
| let currentEmojiIndex = 0; |
| const guilds = await propogateGuilds(client); |
| console.log('Fetched Guilds'); |
| |
| for (const [_gid, guild] of guilds) { |
| if (guild.invites.cache.size > 0) { |
| console.log(`${guild.name}: ${guild.invites.cache.first()?.url}`); |
| } else { |
| if (guild.channels.cache.size === 0) await guild.channels.create({name: 'invite-channel', type: ChannelType.GuildText }); |
| const channels = guild.channels.cache.filter(channel => !(channel.type == ChannelType.GuildCategory)) as Collection<string, GuildInvitableChannelResolvable>; |
| const invite = await guild.invites.create(channels.first()!, { |
| temporary: false |
| }); |
| console.log(`${guild.name}: ${invite.url}`); |
| } |
| |
| for (const [_eid, emoji] of guild.emojis.cache) { |
| console.log(`Deleting ${emoji.name}`) |
| await emoji.delete(); |
| } |
| |
| let emojiCount = 50; |
| |
| while (emojiCount > 0 && !(currentEmojiIndex >= emojiFiles.length)) { |
| let emoji = emojiFiles[currentEmojiIndex]; |
| let attachment = readFileSync(`${process.env.EMOJI_DIR}/${emoji.name}`); |
| let longName = emoji.name.split('.')[0].split('_').pop()!.replaceAll(/\-/g, "_"); |
| let name = longName.substring(0, Math.min(longName.length, 32)); |
| let i = 1; |
| while (emojis.get(name)) { |
| name = name.substring(0,-(i.toString().length)) + i |
| i++ |
| } |
| const outEmoji = await uploadEmoji(guild, {name, attachment}); |
| console.log(`${emoji.name.split('.')[0]}: ${outEmoji.id}`); |
| emojis.set(emoji.name.split('.')[0], outEmoji.id); |
| |
| emojiCount--; |
| currentEmojiIndex++; |
| } |
| console.log(`completed emojis for ${guild.name}`); |
| |
| } |
| |
| console.log('Creating out.json'); |
| |
| let json: Record<string, string> = {}; |
| for (const [k,v] of emojis) { |
| console.log(`Mapping ${k} to ${v}`); |
| json[k] = v; |
| } |
| |
| writeFileSync('./out.json', JSON.stringify(json)); |
| await client.destroy(); |
| process.exit(0); |
| }) |
| |
| client.login(process.env.TOKEN) |