Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TempVoice sous stéroïdes #66

Merged
merged 35 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d6030b2
WIP: create command
adan-ea Sep 1, 2023
ced9dc1
Merge branch 'main' into 38-command-to-setup-modules
adan-ea Sep 12, 2023
07a907a
Merge pull request #43 from adan-ea/main
adan-ea Sep 12, 2023
f8cc96f
Merge pull request #52 from adan-ea/main
adan-ea Sep 15, 2023
94d7819
Merge branch 'main' into 38-command-to-setup-modules
adan-ea Sep 18, 2023
3e4bf78
Merge pull request #56 from adan-ea/main
adan-ea Sep 18, 2023
f9469f4
Merge branch '38-command-to-setup-modules' of github.com:adan-ea/adro…
adan-ea Sep 18, 2023
e310a50
refacto: Update module handling. require=> imports
adan-ea Oct 27, 2023
7f384e3
refacto(components): Move to respective file
adan-ea Oct 27, 2023
9d7a43f
fix(models): remove 'required' causing errors
adan-ea Oct 30, 2023
82b9937
wip: Add new QOTD and temporary voice setup
adan-ea Nov 13, 2023
dee81e5
Merge branch 'main' into 38-command-to-setup-modules
adan-ea Nov 13, 2023
fb80198
wip(qotd): Setup module
adan-ea Nov 13, 2023
01e4707
Merge branch 'main' into 38-command-to-setup-modules
adan-ea Nov 14, 2023
68b3faa
fix(#62): Add limit - needs to be tested
adan-ea Nov 14, 2023
f93264b
deps: upgrade djs & ts + clean
adan-ea Nov 15, 2023
67c8af3
fix: Add async/await to readCommands function
adan-ea Nov 15, 2023
8764fb8
wip(qotd): Update with new channel selection
adan-ea Nov 15, 2023
a86e2e3
Refacto: environment variables and embed field
adan-ea Nov 16, 2023
d1350d1
test: Add unit tests for embedsUtil functions
adan-ea Nov 16, 2023
4351cf0
feat(#59 #60): update tempVoice (mainly)
adan-ea Nov 20, 2023
af96352
refacto: rename values
adan-ea Nov 22, 2023
6ff5aba
refacto: add consts for meaningless ids
adan-ea Nov 22, 2023
e96057b
feat: add a report command
adan-ea Nov 22, 2023
523c14e
feat(tempVoice): Add region, white/blacklist logic
adan-ea Nov 22, 2023
e4f3768
feat(tempVoice): add temporary whitelist
adan-ea Nov 22, 2023
969c8e1
rebase: isn't reliable. Needs website :(
adan-ea Nov 22, 2023
90d3c0e
fix: editReply instead of update
adan-ea Nov 22, 2023
691b98b
refacto: Refactor add documentation
adan-ea Nov 24, 2023
7041a4d
feat(#64): Add changelog command
adan-ea Nov 24, 2023
217a7ea
Fix temporary voice module user settings
adan-ea Nov 24, 2023
6d78314
Update emojis
adan-ea Nov 24, 2023
d2720a4
fix(tempVoice): Update cooldown
adan-ea Nov 24, 2023
ff38209
Fix Twitch access token check and update Twitch
adan-ea Nov 24, 2023
a584693
refactor: Run prettier & eslint
adan-ea Nov 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .github/workflows/issue_tracker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ on:
types: [opened, reopened, labeled, unlabeled, closed]

env:
todo: ✏️ To do
done: ✅ Done
wip: 🚧 In Progress
nth: ✨ NTH
debug: true
todo: ✏️To do
done: ✅Done
wip: 🚧In Progress
nth: 📓Backlog

jobs:
issue_opened_or_reopened:
Expand Down
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,34 +48,36 @@ I self-host the bot but my code isn't yet strong enough to give an invitation li

### 🎉 Party Mode

>🚧 WIP, it will come... soon enough
>🚧 WIP, it will come back... soon enough

### ❓ QotD (Question of the Day)

- Everyday, sends a new question in the channel of your choice and pin it. (Provided there are questions in the database)

![qotd](/assets/qotd/qotd.png)

- People can give their own questions

![qotd](/assets/qotd/request.png)


### 🎤 SwiftVoice

### 🎤 TempVoice

- Auto manage voice channels, deletes and creates channels so only one is needed
![create](/assets/swiftVoice/create.gif)
![create](/assets/tempVoice/create.gif)

The voice owner can :
- Lock the channel to everyone
![lock](/assets/swiftVoice/lock.gif)
![lock](/assets/tempVoice/lock.gif)

- Transfer ownership
![transfer-ownership](/assets/swiftVoice/transfer-ownership.gif)
![transfer-ownership](/assets/tempVoice/transfer-ownership.gif)

- Ban someone in particular (will kick them out)
![voice-ban](/assets/swiftVoice/voice-ban.gif)
![voice-ban](/assets/tempVoice/voice-ban.gif)

- Set a user limit to the channel
![limit](/assets/swiftVoice/limit.gif)
![limit](/assets/tempVoice/limit.gif)

### 📺 Twitch

Expand Down
197 changes: 101 additions & 96 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"dependencies": {
"ansis": "^1.5.5",
"bullmq": "^3.12.0",
"discord.js": "^14.11.0",
"discord.js": "^14.14.1",
"dotenv": "^16.0.3",
"ioredis": "^5.3.2",
"mongoose": "^7.5.0",
Expand All @@ -50,6 +50,6 @@
"lint-staged": "^13.2.2",
"prettier": "^2.8.4",
"ts-jest": "^29.1.1",
"typescript": "^5.1.6"
"typescript": "^5.2.2"
}
}
9 changes: 7 additions & 2 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Client, ClientOptions, Collection } from 'discord.js';

interface ItempVoiceSettings {
ownerId: string;
isPublic: boolean;
}

export interface IDiscordClient {
commands: Collection<string, any>;
buttons: Collection<string, any>;
modals: Collection<string, any>;
selectMenus: Collection<string, any>;
cooldowns: Collection<string, any>;
tempVoice: Collection<string, any>;
tempVoice: Collection<string, ItempVoiceSettings>;
}

export default class DiscordClient extends Client implements IDiscordClient {
Expand All @@ -15,7 +20,7 @@ export default class DiscordClient extends Client implements IDiscordClient {
public modals: Collection<string, any>;
public selectMenus: Collection<string, any>;
public cooldowns: Collection<string, any>;
public tempVoice: Collection<string, any>;
public tempVoice: Collection<string, ItempVoiceSettings>;

constructor(options: ClientOptions) {
super(options);
Expand Down
4 changes: 4 additions & 0 deletions src/delete-commands.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { REST, Routes } from 'discord.js';
import Logger from './utils/logger';

/**
* Deletes all global application commands.
* @param clientId The ID of the Discord client.
*/
export const deleteCMD = async (clientId: string) => {
const rest = new REST().setToken(process.env.DISCORD_TOKEN!);

Expand Down
66 changes: 36 additions & 30 deletions src/deploy-commands.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,64 @@
import { REST, Routes } from 'discord.js';
import { Guilds } from './utils/consts';
import Logger from './utils/logger';
import { OWNER_SERVER_ID } from './utils/consts';
import dotenv from 'dotenv';
import fs from 'fs';
import path from 'node:path';

dotenv.config();
export const regCMD = (clientId: string) => {

/**
* Registers application commands and guild application commands.
* @param clientId The client ID of the Discord bot.
*/
export const regCMD = async (clientId: string) => {
const commands: any[] = [];
const guildCommands: any[] = [];

const categoryFolders = [
path.join(__dirname, 'modules/core/commands'),
//path.join(__dirname, 'modules/twitchLive/commands'),
path.join(__dirname, 'modules/qotd/commands'),
path.join(__dirname, 'modules/tempVoice/commands'),
path.join(__dirname, 'modules/scheduledEvents/commands')
//path.join(__dirname, 'modules/scheduledEvents/commands'),
path.join(__dirname, 'modules/tempVoice/commands')
//path.join(__dirname, 'modules/twitchLive/commands'),
];

const readCommands = (dir: string) => {
const files = fs.readdirSync(dir);
const readCommands = async (dir: string) => {
try {
const files = fs.readdirSync(dir);

for (const file of files) {
const filePath = path.join(dir, file);
const stat = fs.lstatSync(filePath);
const promises = files.map(async file => {
const filePath = path.join(dir, file);
const stat = fs.lstatSync(filePath);

if (stat.isDirectory()) {
readCommands(filePath);
} else if (file.endsWith('.js')) {
const command = require(filePath);
if (stat.isDirectory()) {
return readCommands(filePath);
} else if (file.endsWith('.js')) {
const { default: command } = await import(filePath);
command.data.dmPermission = false;
if (command.guildOnly) guildCommands.push(command.data);
else commands.push(command.data);
}
});

if (command.guildOnly) guildCommands.push(command.data);
else commands.push(command.data);
}
await Promise.all(promises);
} catch (error: any) {
Logger.error('Error while reading commands', error);
}
};
for (const cmdPath of categoryFolders) {
readCommands(cmdPath);
}

await Promise.all(categoryFolders.map(readCommands));

const rest = new REST().setToken(process.env.DISCORD_TOKEN!);

try {
rest.put(Routes.applicationGuildCommands(clientId, OWNER_SERVER_ID), {
await rest.put(Routes.applicationGuildCommands(clientId, Guilds.adan_ea), {
body: guildCommands
}).then(() =>
Logger.info(
`Successfully registered ${guildCommands.length} guild application commands.`
)
);

rest.put(Routes.applicationCommands(clientId), { body: commands }).then(() =>
Logger.info(`Successfully registered ${commands.length} application commands.`)
);
});
Logger.info(`Successfully registered ${guildCommands.length} guild application commands.`);

await rest.put(Routes.applicationCommands(clientId), { body: commands });
Logger.info(`Successfully registered ${commands.length} application commands.`);
} catch (error: any) {
Logger.error('Error while registering application commands', error);
}
Expand Down
19 changes: 16 additions & 3 deletions src/handlers/commandHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,24 @@ import Logger from '../utils/logger';
import fs from 'fs';
import path from 'path';

export const handleCommand = (client: any, cmdPath: string): number => {
/**
* Handles commands recursively in the specified directory path.
* @param client - The client object.
* @param cmdPath - The path to the directory containing the commands.
* @returns A promise that resolves to the number of commands handled.
*/
export const handleCommand = async (client: any, cmdPath: string): Promise<number> => {
let result = 0;
const files = fs.readdirSync(cmdPath);

for (const file of files) {
const filePath = path.join(cmdPath, file);
const stat = fs.lstatSync(filePath);

if (stat.isDirectory()) {
result += handleCommand(client, filePath);
result += await handleCommand(client, filePath);
} else if (file.endsWith('.js')) {
const cmd = require(filePath);
const { default: cmd } = await import(filePath);

const hasWarning = checkCommandOptions(cmd, filePath);
if (!hasWarning) {
Expand All @@ -24,6 +31,12 @@ export const handleCommand = (client: any, cmdPath: string): number => {
return result;
};

/**
* Checks the command options for validity.
* @param cmd - The command object to check.
* @param filePath - The file path of the command handler.
* @returns Returns true if there are errors, false otherwise.
*/
const checkCommandOptions = (cmd: any, filePath: string): boolean => {
let hasWarning = false;
let hasError = false;
Expand Down
40 changes: 34 additions & 6 deletions src/handlers/componentHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,55 @@ import Logger from '../utils/logger';
import fs from 'fs';
import path from 'path';

export const handleComponents = (client: any, compPath: string): Record<string, number> => {
/**
* Handles the components in the specified path.
* @param client - The client object.
* @param compPath - The path to the components.
* @returns A promise that resolves to a record containing the names of the subfolders and the number of subcomponents in each folder.
*/
export const handleComponents = async (
client: any,
compPath: string
): Promise<Record<string, number>> => {
const result: Record<string, number> = {};

const subFolders = fs.readdirSync(compPath);

for (const subFolder of subFolders) {
const stat = fs.lstatSync(path.join(compPath, subFolder));

if (stat.isDirectory()) {
result[subFolder] = handleSubComponent(client, compPath, subFolder);
result[subFolder] = await handleSubComponent(client, compPath, subFolder);
}
}

return result;
};

const handleSubComponent = (client: any, compPath: string, compFolder: string): number => {
/**
* Handles sub-components recursively and adds valid components to the client.
* @param client - The client object.
* @param compPath - The path of the main component.
* @param compFolder - The folder name of the main component.
* @returns The number of valid components added to the client.
*/
const handleSubComponent = async (
client: any,
compPath: string,
compFolder: string
): Promise<number> => {
let result = 0;
const subCompPath = path.join(compPath, compFolder);
const files = fs.readdirSync(subCompPath);

for (const file of files) {
const filePath = path.join(subCompPath, file);
const stat = fs.lstatSync(filePath);

if (stat.isDirectory()) {
result += handleSubComponent(client, subCompPath, file);
} else if (file.endsWith('.js')) {
const component = require(filePath);
result += await handleSubComponent(client, subCompPath, file);
} else if (['Btn.js', 'Menu.js', 'Modal.js'].some(extension => file.endsWith(extension))) {
const { default: component } = await import(filePath);

const hasWarning = checkComponentOptions(component, filePath);
if (!hasWarning) {
Expand All @@ -41,6 +63,12 @@ const handleSubComponent = (client: any, compPath: string, compFolder: string):
return result;
};

/**
* Checks the options of a component.
* @param component - The component to check.
* @param filePath - The file path of the component.
* @returns True if there are errors in the component options, false otherwise.
*/
const checkComponentOptions = (component: any, filePath: string): boolean => {
let hasError = false;
const errorList: string[] = [];
Expand Down
14 changes: 11 additions & 3 deletions src/handlers/eventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@ import Logger from '../utils/logger';
import fs from 'fs';
import path from 'path';

export const handleEvent = (client: Client, eventPath: string): number => {
/**
* Handles events recursively in the specified event path.
* @param client - The client object.
* @param eventPath - The path to the events directory.
* @returns A promise that resolves to the number of events handled.
*/
export const handleEvent = async (client: Client, eventPath: string): Promise<number> => {
let result = 0;
const files = fs.readdirSync(eventPath);

for (const file of files) {
const filePath = path.join(eventPath, file);
const stat = fs.lstatSync(filePath);

if (stat.isDirectory()) {
result += handleEvent(client, filePath);
result += await handleEvent(client, filePath);
} else if (file.endsWith('.js')) {
const event = require(filePath);
const { default: event } = await import(filePath);

if (event.once) {
client.once(event.name, (...args: any) => event.execute(client, ...args));
} else {
Expand Down
Loading