diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..22ebc2a --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +DISCORD_TOKEN=a +CLIENT_ID=b diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..16208e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.vscode/ +.env diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d323bfc --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 isabelroses + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6eb1e31 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# Blahaj + +

+
+ BlÄhaj +

+ +Blahaj is a simple discord bot that is designed to do anything that you want it to do. It is written in JavaScript and uses the discord.js library. + +## Installation + +To install blahaj, you need to have node.js installed. You can download it from [here](https://nodejs.org/en/download/). Once you have node.js installed, you can install blahaj by running the following command: + +Then navigate to the file and run the following command: +```bash +npm install +``` +This will install all the dependencies that blahaj needs to run. + +## Usage + +To run blahaj +```bash +node src/index.js +``` + + +## Thanks + +Thanks to [discord.js](https://discord.js.org/#/) for making this bot possible. + +Thanks to this [reddit post](https://www.reddit.com/r/BLAHAJ/comments/s91n8d/some_blahaj_emojis/) for the emojis. diff --git a/assets/BigBlobhajHug.svg b/assets/BigBlobhajHug.svg new file mode 100644 index 0000000..61aa622 --- /dev/null +++ b/assets/BigBlobhajHug.svg @@ -0,0 +1,6696 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..835e693 --- /dev/null +++ b/default.nix @@ -0,0 +1,11 @@ +{buildNpmPackage}: +buildNpmPackage { + pname = "blahaj"; + version = "0.1.0"; + + src = ./.; + + dontNpmBuild = true; + + npmDepsHash = "sha256-mRmu2UIJTWj4d/UypUAM4+3Q8cbuVpazMuv4b21Yxho="; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..bd4037a --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1710795924, + "narHash": "sha256-Cy5wSZkv1Ts0CD6Tk1mXMNE/Aa0+MGsKTRDak16qcoE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b081342f1c16e4cbe4f40f139bbdda1475ea306a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..41d3e52 --- /dev/null +++ b/flake.nix @@ -0,0 +1,26 @@ +{ + description = "Blahaj"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = { + self, + nixpkgs, + }: let + systems = ["x86_64-linux" "aarch64-linux"]; + forEachSystem = nixpkgs.lib.genAttrs systems; + + pkgsForEach = nixpkgs.legacyPackages; + in { + packages = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./default.nix {}; + }); + + devShells = forEachSystem (system: { + default = pkgsForEach.${system}.callPackage ./shell.nix {}; + }); + + nixosModules.default = import ./module.nix self; + }; +} diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..cb62730 --- /dev/null +++ b/module.nix @@ -0,0 +1,26 @@ +self: { + pkgs, + config, + lib, + ... +}: let + inherit (lib) mkIf mkEnableOption; +in { + options.services.blahaj.enable = mkEnableOption "blahaj"; + + config = mkIf config.services.blahaj.enable { + systemd.services."blahaj" = { + description = "blahaj"; + after = ["network.target"]; + wantedBy = ["multi-user.target"]; + path = [pkgs.nodejs]; + + serviceConfig = { + Type = "simple"; + DynamicUser = true; + ExecStart = "node ${self.packages.${pkgs.stdenv.hostPlatform.system}.default}/lib/node_modules/blahaj"; + Restart = "always"; + }; + }; + }; +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..db2a7a1 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,612 @@ +{ + "name": "blowhigh", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "blowhigh", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@discordjs/rest": "^1.6.0", + "chalk": "^4.1.2", + "discord-api-types": "^0.37.36", + "discord.js": "^14.8.0", + "dotenv": "^16.0.3" + } + }, + "node_modules/@discordjs/builders": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.7.0.tgz", + "integrity": "sha512-GDtbKMkg433cOZur8Dv6c25EHxduNIBsxeHrsRoIM8+AwmEZ8r0tEpckx/sHwTLwQPOF3e2JWloZh9ofCaMfAw==", + "dependencies": { + "@discordjs/formatters": "^0.3.3", + "@discordjs/util": "^1.0.2", + "@sapphire/shapeshift": "^3.9.3", + "discord-api-types": "0.37.61", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/builders/node_modules/@discordjs/util": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz", + "integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/builders/node_modules/discord-api-types": { + "version": "0.37.61", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz", + "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==" + }, + "node_modules/@discordjs/collection": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.5.3.tgz", + "integrity": "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@discordjs/formatters/-/formatters-0.3.3.tgz", + "integrity": "sha512-wTcI1Q5cps1eSGhl6+6AzzZkBBlVrBdc9IUhJbijRgVjCNIIIZPgqnUj3ntFODsHrdbGU8BEG9XmDQmgEEYn3w==", + "dependencies": { + "discord-api-types": "0.37.61" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/formatters/node_modules/discord-api-types": { + "version": "0.37.61", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz", + "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==" + }, + "node_modules/@discordjs/rest": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-1.7.1.tgz", + "integrity": "sha512-Ofa9UqT0U45G/eX86cURQnX7gzOJLG2oC28VhIk/G6IliYgQF7jFByBJEykPSHE4MxPhqCleYvmsrtfKh1nYmQ==", + "dependencies": { + "@discordjs/collection": "^1.5.1", + "@discordjs/util": "^0.3.0", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.4.2", + "discord-api-types": "^0.37.41", + "file-type": "^18.3.0", + "tslib": "^2.5.0", + "undici": "^5.22.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/util": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.3.1.tgz", + "integrity": "sha512-HxXKYKg7vohx2/OupUN/4Sd02Ev3PBJ5q0gtjdcvXb0ErCva8jNHWfe/v5sU3UKjIB/uxOhc+TDOnhqffj9pRA==", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/ws": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.0.2.tgz", + "integrity": "sha512-+XI82Rm2hKnFwAySXEep4A7Kfoowt6weO6381jgW+wVdTpMS/56qCvoXyFRY0slcv7c/U8My2PwIB2/wEaAh7Q==", + "dependencies": { + "@discordjs/collection": "^2.0.0", + "@discordjs/rest": "^2.1.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@types/ws": "^8.5.9", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "tslib": "^2.6.2", + "ws": "^8.14.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/collection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", + "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/rest": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.2.0.tgz", + "integrity": "sha512-nXm9wT8oqrYFRMEqTXQx9DUTeEtXUDMmnUKIhZn6O2EeDY9VCdwj23XCPq7fkqMPKdF7ldAfeVKyxxFdbZl59A==", + "dependencies": { + "@discordjs/collection": "^2.0.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "magic-bytes.js": "^1.5.0", + "tslib": "^2.6.2", + "undici": "5.27.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws/node_modules/@discordjs/util": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz", + "integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/@discordjs/ws/node_modules/discord-api-types": { + "version": "0.37.61", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz", + "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==" + }, + "node_modules/@discordjs/ws/node_modules/undici": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@sapphire/async-queue": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@sapphire/async-queue/-/async-queue-1.5.2.tgz", + "integrity": "sha512-7X7FFAA4DngXUl95+hYbUF19bp1LGiffjJtu7ygrZrbdCSsdDDBaSjB7Akw0ZbOu6k0xpXyljnJ6/RZUvLfRdg==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/shapeshift": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.9.6.tgz", + "integrity": "sha512-4+Na/fxu2SEepZRb9z0dbsVh59QtwPuBg/UVaDib3av7ZY14b14+z09z6QVn0P6Dv6eOU2NDTsjIi0mbtgP56g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@sapphire/snowflake": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.3.tgz", + "integrity": "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, + "node_modules/@types/node": { + "version": "20.11.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz", + "integrity": "sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/ws": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.9.tgz", + "integrity": "sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vladfrangu/async_event_emitter": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.4.tgz", + "integrity": "sha512-ButUPz9E9cXMLgvAW8aLAKKJJsPu1dY1/l/E8xzLFuysowXygs6GBcyunK9rnGC4zTsnIc2mQo71rGw9U+Ykug==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/discord-api-types": { + "version": "0.37.75", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.75.tgz", + "integrity": "sha512-pnb2iPp63+TqSs+3MCzl47y0CFQYjDDQBmuiCs0LkLoRdFx2dDpjrzJYC7BcHJCa/Xlpf+/JuDT/YADvQLu3yQ==" + }, + "node_modules/discord.js": { + "version": "14.14.1", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.14.1.tgz", + "integrity": "sha512-/hUVzkIerxKHyRKopJy5xejp4MYKDPTszAnpYxzVVv4qJYf+Tkt+jnT2N29PIPschicaEEpXwF2ARrTYHYwQ5w==", + "dependencies": { + "@discordjs/builders": "^1.7.0", + "@discordjs/collection": "1.5.3", + "@discordjs/formatters": "^0.3.3", + "@discordjs/rest": "^2.1.0", + "@discordjs/util": "^1.0.2", + "@discordjs/ws": "^1.0.2", + "@sapphire/snowflake": "3.5.1", + "@types/ws": "8.5.9", + "discord-api-types": "0.37.61", + "fast-deep-equal": "3.1.3", + "lodash.snakecase": "4.1.1", + "tslib": "2.6.2", + "undici": "5.27.2", + "ws": "8.14.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/rest": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.2.0.tgz", + "integrity": "sha512-nXm9wT8oqrYFRMEqTXQx9DUTeEtXUDMmnUKIhZn6O2EeDY9VCdwj23XCPq7fkqMPKdF7ldAfeVKyxxFdbZl59A==", + "dependencies": { + "@discordjs/collection": "^2.0.0", + "@discordjs/util": "^1.0.2", + "@sapphire/async-queue": "^1.5.0", + "@sapphire/snowflake": "^3.5.1", + "@vladfrangu/async_event_emitter": "^2.2.2", + "discord-api-types": "0.37.61", + "magic-bytes.js": "^1.5.0", + "tslib": "^2.6.2", + "undici": "5.27.2" + }, + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/rest/node_modules/@discordjs/collection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-2.0.0.tgz", + "integrity": "sha512-YTWIXLrf5FsrLMycpMM9Q6vnZoR/lN2AWX23/Cuo8uOOtS8eHB2dyQaaGnaF8aZPYnttf2bkLMcXn/j6JUOi3w==", + "engines": { + "node": ">=18" + } + }, + "node_modules/discord.js/node_modules/@discordjs/util": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-1.0.2.tgz", + "integrity": "sha512-IRNbimrmfb75GMNEjyznqM1tkI7HrZOf14njX7tCAAUetyZM1Pr8hX/EK2lxBCOgWDRmigbp24fD1hdMfQK5lw==", + "engines": { + "node": ">=16.11.0" + } + }, + "node_modules/discord.js/node_modules/@sapphire/snowflake": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@sapphire/snowflake/-/snowflake-3.5.1.tgz", + "integrity": "sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/discord.js/node_modules/discord-api-types": { + "version": "0.37.61", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.61.tgz", + "integrity": "sha512-o/dXNFfhBpYHpQFdT6FWzeO7pKc838QeeZ9d91CfVAtpr5XLK4B/zYxQbYgPdoMiTDvJfzcsLW5naXgmHGDNXw==" + }, + "node_modules/discord.js/node_modules/undici": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/file-type": { + "version": "18.7.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-18.7.0.tgz", + "integrity": "sha512-ihHtXRzXEziMrQ56VSgU7wkxh55iNchFkosu7Y9/S+tXHdKyrGjVK0ujbqNnsxzea+78MaLhN6PGmfYSAv1ACw==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0", + "token-types": "^5.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" + }, + "node_modules/magic-bytes.js": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz", + "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==" + }, + "node_modules/peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/ts-mixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/undici": { + "version": "5.28.3", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.3.tgz", + "integrity": "sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5b268f9 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "dependencies": { + "@discordjs/rest": "^1.6.0", + "chalk": "^4.1.2", + "discord-api-types": "^0.37.36", + "discord.js": "^14.8.0", + "dotenv": "^16.0.3" + }, + "name": "blahaj", + "version": "1.0.0", + "main": "src/bot.js", + "scripts": { + "start": "node ." + }, + "author": "isabelroses", + "license": "MIT", + "description": "A silly little discord bot" +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..82f6383 --- /dev/null +++ b/shell.nix @@ -0,0 +1,24 @@ +{ + eslint_d, + prettierd, + callPackage, + writeShellScriptBin, +}: let + mainPkg = callPackage ./default.nix {}; + mkNpxAlias = name: writeShellScriptBin name "npx ${name} \"$@\""; +in + mainPkg.overrideAttrs (oa: { + nativeBuildInputs = + [ + eslint_d + prettierd + (mkNpxAlias "tsc") + (mkNpxAlias "tsserver") + ] + ++ (oa.nativeBuildInputs or []); + + shellHook = '' + eslint_d start # start eslint daemon + eslint_d status # inform user about eslint daemon status + ''; + }) diff --git a/src/bot.js b/src/bot.js new file mode 100644 index 0000000..2eaa8d7 --- /dev/null +++ b/src/bot.js @@ -0,0 +1,19 @@ +require('dotenv').config(); +const { Client, Collection, GatewayIntentBits } = require('discord.js'); +const fs = require('fs'); + + +const client = new Client({ intents: GatewayIntentBits.Guilds }); +client.commands = new Collection(); +client.commandArray = []; +client.buttons = new Collection(); + +const functionFolders = fs.readdirSync('./src/functions'); +for (const folder of functionFolders) { + const functionFiles = fs.readdirSync(`./src/functions/${folder}`).filter(file => file.endsWith('.js')); + for (const file of functionFiles) require(`./functions/${folder}/${file}`)(client); +} + +client.handleComponents(); +client.handleEvents(); +client.login(process.env.DISCORD_TOKEN); diff --git a/src/commands/help/help.js b/src/commands/help/help.js new file mode 100644 index 0000000..ef46554 --- /dev/null +++ b/src/commands/help/help.js @@ -0,0 +1,99 @@ +const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('help') + .setDescription('Replies with Help!'), + async execute(interaction, client) { + const embed = new EmbedBuilder() + .setTitle('Help') + .setColor([255, 255, 255]) + .setThumbnail(client.user.displayAvatarURL({ dynamic: true })) + .setDescription('This is a list of all the commands available to you.') + .addFields({ name: 'Page 1', value: 'Help & Resources' }) + .addFields({ name: 'Page 2', value: 'Tools' }) + .addFields({ name: 'Page 3', value: 'Fun' }) + .addFields({ name: 'Page 4', value: 'Moderattion' }) + + const embed2 = new EmbedBuilder() + .setTitle('Help') + .setColor([255, 255, 255]) + .setThumbnail(client.user.displayAvatarURL({ dynamic: true })) + .setDescription('This is a list of all the commands available to you.') + .addFields({ name: '/help', value: 'Do /help for this page' }) + .addFields({ name: '/ping', value: 'Do /ping to get the bot\'s ping' }) + .addFields({ name: '/invite', value: 'Do /invite to get the bot\'s invite link' }) + + const embed3 = new EmbedBuilder() + .setTitle('Help') + .setColor([255, 255, 255]) + .setThumbnail(client.user.displayAvatarURL({ dynamic: true })) + .setDescription('This is a list of all the commands available to you.') + .addFields({ name: '/whois', value: 'Do /whois to get a the user information of a given user' }) + .addFields({ name: '/avatar', value: 'Do /avatar to get a the avatar of a given user' }) + .addFields({ name: '/serverinfo', value: 'Do /serverinfo to get the server information' }) + .addFields({ name: '/botinfo', value: 'Do /botinfo to get the bot information' }) + .addFields({ name: '/embed', value: 'Do /emebed to help you make a embed' }) + + const embed4 = new EmbedBuilder() + .setTitle('Help') + .setColor([255, 255, 255]) + .setThumbnail(client.user.displayAvatarURL({ dynamic: true })) + .setDescription('This is a list of all the commands available to you.') + .addFields({ name: '/kick', value: 'Do /kick to kick a user' }) + .addFields({ name: '/ban', value: 'Do /ban to ban a user' }) + .addFields({ name: '/timeout', value: 'Do /timeout to timeout a user' }) + .addFields({ name: '/untimeout', value: 'Do /untimeout to untimeout a user' }) + .addFields({ name: '/clear', value: 'Do /clear to clear a given amount of messages' }) + + const buttons = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setLabel('Page 1') + .setStyle('Primary') + .setCustomId('page1'), + new ButtonBuilder() + .setLabel('Page 2') + .setStyle('Primary') + .setCustomId('page2'), + new ButtonBuilder() + .setLabel('Page 3') + .setStyle('Primary') + .setCustomId('page3'), + new ButtonBuilder() + .setLabel('Page 4') + .setStyle('Primary') + .setCustomId('page4') + ) + + const message = await interaction.reply({ embeds: [embed], components: [buttons] }); + const collector = await message.createMessageComponentCollector(); + + collector.on('collect', async i => { + if (i.customId === `page1`) { + if (i.user.id !== interaction.user.id) { + return await i.update({ content: `Only ${interaction.user.tag} can use these buttons!`, ephemeral: true }); + } + await i.update({ embeds: [embed], components: [buttons] }); + } + if (i.customId === `page2`) { + if (i.user.id !== interaction.user.id) { + return await i.update({ content: `Only ${interaction.user.tag} can use these buttons!`, ephemeral: true }); + } + await i.update({ embeds: [embed2], components: [buttons] }); + } + if (i.customId === `page3`) { + if (i.user.id !== interaction.user.id) { + return await i.update({ content: `Only ${interaction.user.tag} can use these buttons!`, ephemeral: true }); + } + await i.update({ embeds: [embed3], components: [buttons] }); + } + if (i.customId === `page4`) { + if (i.user.id !== interaction.user.id) { + return await i.update({ content: `Only ${interaction.user.tag} can use these buttons!`, ephemeral: true }); + } + await i.update({ embeds: [embed4], components: [buttons] }); + } + }); + } +}; diff --git a/src/commands/help/invite.js b/src/commands/help/invite.js new file mode 100644 index 0000000..6d7e6a9 --- /dev/null +++ b/src/commands/help/invite.js @@ -0,0 +1,10 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('invite') + .setDescription('Replies with the bot\'s invite link!'), + async execute(interaction) { + await interaction.reply({ content: 'https://discord.com/api/oauth2/authorize?client_id=1087418361283092510&permissions=8&scope=bot%20applications.commands' }); + }, +}; \ No newline at end of file diff --git a/src/commands/help/ping.js b/src/commands/help/ping.js new file mode 100644 index 0000000..80baac1 --- /dev/null +++ b/src/commands/help/ping.js @@ -0,0 +1,17 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('ping') + .setDescription('Replies with Pong!'), + async execute(interaction, client) { + const msg = await interaction.deferReply({ + fetchReply: true + }); + + const newMessage = `API Latency is ${Math.round(client.ws.ping)}ms\nMessage Latency is ${msg.createdTimestamp - interaction.createdTimestamp}ms`; + await interaction.editReply({ + content: newMessage + }); + } +}; \ No newline at end of file diff --git a/src/commands/moderation/ban.js b/src/commands/moderation/ban.js new file mode 100644 index 0000000..b592fb9 --- /dev/null +++ b/src/commands/moderation/ban.js @@ -0,0 +1,32 @@ +const { SlashCommandBuilder, PermissionsBitField } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('ban') + .setDescription('Bans a user') + .setDefaultMemberPermissions(PermissionsBitField.Flags.BanMembers) + .addUserOption(option => option.setName('target').setDescription('The user to ban').setRequired(true)) + .addStringOption(option => option.setName('reason').setDescription('The reason for the ban').setRequired(false)), + async execute(interaction) { + const user = interaction.options.getUser('target'); + const member = await interaction.guild.members.fetch(user.id).catch(console.error); + let reason = interaction.options.getString('reason'); + if (!reason) reason = 'No reason provided'; + + if (!interaction.member.permissions.has(PermissionsBitField.Flags.BanMembers)) return await interaction.reply({ content: 'You do not have permission to ban this user', ephemeral: true }) + if (!member.kickable) return await interaction.reply({ content: 'This user cannot be banned', ephemeral: true }) + if (!member) return await interaction.reply({ content: `User ${user.tag} is not in this server`, ephemeral: true }) + if (interaction.member.id === user.id) return await interaction.reply({ content: 'You cannot ban yourself', ephemeral: true }) + if (member.permissions.has(PermissionsBitField.Flags.Administrator)) return await interaction.reply({ content: 'You cannot ban this user', ephemeral: true }) + + user.send(`You have been banned from ${interaction.guild.name} for ${reason}`).catch(console.log("Dm's are disabled for this user")); + await member.ban({ + deleteMessageSeconds: 60 * 60 * 24 * 7, + reason: reason, + }).catch(console.error); + await interaction.reply({ + content: `Banned ${user.tag} for ${reason}`, + ephemeral: true + }) + } +}; diff --git a/src/commands/moderation/kick.js b/src/commands/moderation/kick.js new file mode 100644 index 0000000..1f1c886 --- /dev/null +++ b/src/commands/moderation/kick.js @@ -0,0 +1,29 @@ +const { SlashCommandBuilder, PermissionsBitField } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('kick') + .setDescription('Kicks a user') + .setDefaultMemberPermissions(PermissionsBitField.Flags.KickMembers) + .addUserOption(option => option.setName('target').setDescription('The user to kick').setRequired(true)) + .addStringOption(option => option.setName('reason').setDescription('The reason for the kick').setRequired(false)), + async execute(interaction) { + const user = interaction.options.getUser('target'); + const member = await interaction.guild.members.fetch(user.id).catch(console.error); + let reason = interaction.options.getString('reason'); + if (!reason) reason = 'No reason provided'; + + if (!interaction.member.permissions.has(PermissionsBitField.Flags.KickMembers)) return await interaction.reply({ content: 'You do not have permission to kick this user', ephemeral: true }) + if (!member.kickable) return await interaction.reply({ content: 'This user cannot be kicked', ephemeral: true }) + if (!member) return await interaction.reply({ content: `User ${user.tag} is not in this server`, ephemeral: true }) + if (interaction.member.id === user.id) return await interaction.reply({ content: 'You cannot kick yourself', ephemeral: true }) + if (member.permissions.has(PermissionsBitField.Flags.Administrator)) return await interaction.reply({ content: 'You cannot kick this user', ephemeral: true }) + + user.send(`You have been kicked from ${interaction.guild.name} for ${reason}`).catch(console.error); + await member.kick(`You have been kicked from ${interaction.guild.name} for ${reason}`).catch(console.log("Dm's are disabled for this user")); + await interaction.reply({ + content: `Kicked ${user.tag} for ${reason}`, + ephemeral: true + }) + } +}; diff --git a/src/commands/moderation/purge.js b/src/commands/moderation/purge.js new file mode 100644 index 0000000..1ff1327 --- /dev/null +++ b/src/commands/moderation/purge.js @@ -0,0 +1,27 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); +const { PermissionsBitField } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('purge') + .setDescription('Deletes messages.') + .setDefaultMemberPermissions(PermissionsBitField.Flags.ManageMessages) + .addIntegerOption(option => + option.setName('amount') + .setMinValue(1) + .setMaxValue(100) + .setDescription('The amount of messages to delete.') + .setRequired(true)), + async execute(interaction) { + if (!interaction.member.permissions.has(PermissionsBitField.Flags.ManageMessages)) return await interaction.reply({ content: 'You do not have permission to purge messages', ephemeral: true }) + + let amount = interaction.options.getInteger('amount'); + + await interaction.channel.bulkDelete(amount).catch(err => { + console.error(err); + interaction.reply({ content: 'There was an error trying to purge messages in this channel!', ephemeral: true }); + }); + + await interaction.reply({ content: `Successfully deleted ${amount} messages.`, ephemeral: true }); + } +}; \ No newline at end of file diff --git a/src/commands/moderation/timeout.js b/src/commands/moderation/timeout.js new file mode 100644 index 0000000..5f8144b --- /dev/null +++ b/src/commands/moderation/timeout.js @@ -0,0 +1,41 @@ +const { SlashCommandBuilder, PermissionsBitField } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('timeout') + .setDescription('Times out a user') + .setDefaultMemberPermissions(PermissionsBitField.Flags.ModerateMembers) + .addUserOption(option => option.setName('target').setDescription('The user to time out').setRequired(true)) + .addStringOption(option => option.setName('time').setDescription('The duration to time the user out').setRequired(true).addChoices( + { name: '60 seconds', value: '60' }, + { name: '5 minutes', value: '300' }, + { name: '10 minutes', value: '600' }, + { name: '30 minutes', value: '1800' }, + { name: '1 hour', value: '3600' }, + { name: '12 hours', value: '43200' }, + { name: '1 day', value: '86400' }, + { name: '1 week', value: '604800' }, + { name: '1 month', value: '2629743' } + )) + .addStringOption(option => option.setName('reason').setDescription('The reason for the timeout').setRequired(false)), + async execute(interaction) { + const user = interaction.options.getUser('target'); + const member = await interaction.guild.members.fetch(user.id).catch(console.error); + let reason = interaction.options.getString('reason'); + let time = interaction.options.getString('time'); + if (!time) time = '60'; + if (!reason) reason = 'No reason provided'; + + if (!interaction.member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) return await interaction.reply({ content: 'You do not have permission to timeout this user', ephemeral: true }) + if (!member.kickable) return await interaction.reply({ content: 'This user cannot be timed out', ephemeral: true }) + if (!member) return await interaction.reply({ content: `User ${user.tag} is not in this server`, ephemeral: true }) + if (interaction.member.id === user.id) return await interaction.reply({ content: 'You cannot timeout yourself', ephemeral: true }) + if (member.permissions.has(PermissionsBitField.Flags.Administrator)) return await interaction.reply({ content: 'You cannot timeout this user', ephemeral: true }) + + await member.timeout(time * 1000, reason).catch(console.error); + await interaction.reply({ + content: `Timed out ${user.tag} for ${time} seconds for ${reason}`, + ephemeral: true + }) + } +}; diff --git a/src/commands/moderation/unban.js b/src/commands/moderation/unban.js new file mode 100644 index 0000000..2f08fea --- /dev/null +++ b/src/commands/moderation/unban.js @@ -0,0 +1,28 @@ +const { SlashCommandBuilder, PermissionsBitField } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('unban') + .setDescription('Unbans a user') + .setDefaultMemberPermissions(PermissionsBitField.Flags.BanMembers) + .addUserOption(option => option.setName('target').setDescription('The user to unban').setRequired(true)), + async execute(interaction, client) { + const userid = interaction.options.getUser('target'); + + if (!interaction.member.permissions.has(PermissionsBitField.Flags.BanMembers)) return await interaction.reply({ content: 'You do not have permission to unbanned this user', ephemeral: true }) + if (!member.kickable) return await interaction.reply({ content: 'This user cannot be unbanned out', ephemeral: true }) + if (!member) return await interaction.reply({ content: `User ${user.tag} is not in this server`, ephemeral: true }) + if (interaction.member.id === userid) return await interaction.reply({ content: 'You cannot unbanned yourself', ephemeral: true }) + if (member.permissions.has(PermissionsBitField.Flags.Administrator)) return await interaction.reply({ content: 'You cannot unbanned this user', ephemeral: true }) + + await interactions.guild.ban.fetch().then(async bans => { + if (bans.size == 0) return await interaction.reply({ content: 'There are no banned users in this server', ephemeral: true }); + let bUser = bans.find(b => b.user.id == userid); + if (!bUser) return await interaction.reply({ content: 'This user is not banned', ephemeral: true }); + + await interaction.guild.bans.remove(userid).catch(err => { + return interaction.reply({ content: 'There was an error unbanning this user', ephemeral: true }); + }); + }); + } +}; diff --git a/src/commands/moderation/untimeout.js b/src/commands/moderation/untimeout.js new file mode 100644 index 0000000..fd96fdd --- /dev/null +++ b/src/commands/moderation/untimeout.js @@ -0,0 +1,25 @@ +const { SlashCommandBuilder, PermissionsBitField } = require('discord.js'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('untimeout') + .setDescription('Untimes out a user') + .setDefaultMemberPermissions(PermissionsBitField.Flags.ModerateMembers) + .addUserOption(option => option.setName('target').setDescription('The user to untimeout').setRequired(true)), + async execute(interaction) { + const user = interaction.options.getUser('target'); + const member = await interaction.guild.members.fetch(user.id).catch(console.error); + + if (!interaction.member.permissions.has(PermissionsBitField.Flags.ModerateMembers)) return await interaction.reply({ content: 'You do not have permission to untimeout this user', ephemeral: true }) + if (!member.isTimeout) return await interaction.reply({ content: `User ${user.tag} is not timed out`, ephemeral: true }) + if (!member) return await interaction.reply({ content: `User ${user.tag} is not in this server`, ephemeral: true }) + if (interaction.member.id === user.id) return await interaction.reply({ content: 'You cannot untimeout yourself', ephemeral: true }) + if (member.permissions.has(PermissionsBitField.Flags.Administrator)) return await interaction.reply({ content: 'You cannot untimeout this user', ephemeral: true }) + + await member.timeout(null).catch(console.error); + await interaction.reply({ + content: `Untimed out ${user.tag}`, + ephemeral: true + }) + } +}; diff --git a/src/commands/tools/avatar.js b/src/commands/tools/avatar.js new file mode 100644 index 0000000..06c7399 --- /dev/null +++ b/src/commands/tools/avatar.js @@ -0,0 +1,16 @@ +const { SlashCommandBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('avatar') + .setDescription('Replies with your avatar!') + .addUserOption(option => option.setName('target').setDescription('The user\'s avatar to show')), + async execute(interaction) { + const user = interaction.options.getUser('target'); + if (!user) { + await interaction.reply({ content: `${interaction.user.displayAvatarURL({ dynamic: true })}` }); + } else { + await interaction.reply({ content: `${interaction.options.getUser('target').displayAvatarURL({ dynamic: true })}` }); + } + }, +}; diff --git a/src/commands/tools/botstatus.js b/src/commands/tools/botstatus.js new file mode 100644 index 0000000..279f588 --- /dev/null +++ b/src/commands/tools/botstatus.js @@ -0,0 +1,54 @@ +const { SlashCommandBuilder, EmbedBuilder, ButtonBuilder, ActionRowBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('botstatus') + .setDescription('Gets information about the bot'), + async execute(interaction) { + const bot = interaction.client.user; + const botmem = await interaction.guild.members.fetch(bot.id); + let totalSeconds = (interaction.client.uptime / 1000); + let days = Math.floor(totalSeconds / 86400); + totalSeconds %= 86400; + let hours = Math.floor(totalSeconds / 3600); + totalSeconds %= 3600; + let minutes = Math.floor(totalSeconds / 60); + let seconds = Math.floor(totalSeconds % 60); + let uptime = `${days} days, ${hours} hours, ${minutes} minutes and ${seconds} seconds`; + + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setLabel('Invite') + .setStyle('Link') + .setURL('https://discord.com/api/oauth2/authorize?client_id=1087418361283092510&permissions=8&scope=bot%20applications.commands'), + new ButtonBuilder() + .setLabel('Code') + .setStyle('Link') + .setURL('https://github.com/isabelroses/blahaj') + ) + + const embed = new EmbedBuilder() + .setTitle('Bot Status') + .setColor([255, 255, 255]) + .setThumbnail(bot.displayAvatarURL({ dynamic: true })) + .addFields({ name: 'Created At', value: ``, inline: false }) + .addFields({ name: 'Joined At', value: ``, inline: false }) + .addFields({ name: 'Ping', value: `${Math.round(interaction.client.ws.ping)}ms`, inline: false }) + .addFields({ name: 'Servers', value: `${interaction.client.guilds.cache.size}`, inline: false }) + .addFields({ + name: 'Uptime', value: `\`\`\`${uptime}\`\`\``, inline: true + }) + .addFields({ name: 'Roles', value: `${botmem.roles.cache.map(r => r).join(' ')}`, inline: false }) + .setFooter({ text: "Bot ID: 1087418361283092510" }) + .setTimestamp(Date.now()) + .setAuthor({ + name: bot.tag, + iconURL: bot.displayAvatarURL({ dynamic: true }) + }); + await interaction.reply({ + embeds: [embed], + components: [row] + }) + } +}; \ No newline at end of file diff --git a/src/commands/tools/embed.js b/src/commands/tools/embed.js new file mode 100644 index 0000000..3f04064 --- /dev/null +++ b/src/commands/tools/embed.js @@ -0,0 +1,30 @@ +const { SlashCommandBuilder, EmbedBuilder, Embed } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('embed') + .setDescription('Sends an embed') + .addStringOption(option => option.setName('title').setDescription('The title of the embed').setRequired(true)) + .addStringOption(option => option.setName('description').setDescription('The description of the embed').setRequired(true)) + .addStringOption(option => option.setName('image').setDescription('Image').setRequired(false)), + async execute(interaction, client) { + const embed = new EmbedBuilder() + .setTitle(interaction.options.getString('title')) + .setDescription(interaction.options.getString('description')) + .setThumbnail(interaction.options.getString('image') || null) + .setColor([255, 255, 255]) + .setThumbnail(interaction.guild.iconURL({ dynamic: true })) + .setFooter({ + iconURL: client.user.displayAvatarURL({ dynamic: true }), + text: client.user.tag + }) + .setTimestamp(Date.now()) + .setAuthor({ + name: interaction.user.tag, + iconURL: interaction.user.displayAvatarURL({ dynamic: true }) + }); + await interaction.reply({ + embeds: [embed] + }) + } +}; \ No newline at end of file diff --git a/src/commands/tools/serverinfo.js b/src/commands/tools/serverinfo.js new file mode 100644 index 0000000..1e55c1f --- /dev/null +++ b/src/commands/tools/serverinfo.js @@ -0,0 +1,47 @@ +const { SlashCommandBuilder, EmbedBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('serverinfo') + .setDescription('Replies with server info!'), + async execute(interaction) { + + const { guild } = interaction; + const { name, ownerId, createdAt, memberCount } = guild; + const icon = guild.iconURL({ dynamic: true }); + const roles = guild.roles.cache.size; + const emojies = guild.emojis.cache.size; + const id = guild.id; + + let baseVerification = guild.verificationLevel; + let verificationLevel = ''; + + if (baseVerification == 0) verificationLevel = 'None'; + if (baseVerification == 1) verificationLevel = 'Low'; + if (baseVerification == 2) verificationLevel = 'Medium'; + if (baseVerification == 3) verificationLevel = 'High'; + if (baseVerification == 4) verificationLevel = 'Very High'; + + const embed = new EmbedBuilder() + .setTitle('Server Info') + .setThumbnail(icon) + .addFields({ name: 'Server Name', value: `${name}`, inline: false }) + .addFields({ name: 'Server ID', value: `${id}`, inline: false }) + .addFields({ name: 'Owner', value: `<@${ownerId}>`, inline: false }) + .addFields({ name: 'Created At', value: ``, inline: false }) + .addFields({ name: 'Member Count', value: `${memberCount}`, inline: false }) + .addFields({ name: 'Verification Level', value: `${verificationLevel}`, inline: false }) + .addFields({ name: 'Roles', value: `${roles}`, inline: true }) + .addFields({ name: 'Emojis', value: `${emojies}`, inline: true }) + .addFields({ name: 'Server Boosts', value: `${guild.premiumSubscriptionCount}`, inline: true }) + .setColor([255, 255, 255]) + .setFooter({ + text: interaction.user.tag, + iconURL: interaction.user.displayAvatarURL({ dynamic: true }) + }) + .setTimestamp(Date.now()) + .setAuthor({ name: name, iconURL: icon }); + + await interaction.reply({ embeds: [embed] }); + }, +}; diff --git a/src/commands/tools/whois.js b/src/commands/tools/whois.js new file mode 100644 index 0000000..b7bfe0a --- /dev/null +++ b/src/commands/tools/whois.js @@ -0,0 +1,33 @@ +const { SlashCommandBuilder, EmbedBuilder } = require('@discordjs/builders'); + +module.exports = { + data: new SlashCommandBuilder() + .setName('whois') + .setDescription('Gets information about a user') + .addUserOption(option => option.setName('user').setDescription('The user to get information about').setRequired(false)), + async execute(interaction) { + const user = interaction.options.getUser('user') || interaction.user; + const member = await interaction.guild.members.fetch(user.id); + const embed = new EmbedBuilder() + .setTitle(`${user.username}#${user.discriminator}`) + .setDescription(`ID: ${user.id}`) + .setColor([255, 255, 255]) + .setThumbnail(user.displayAvatarURL({ dynamic: true })) + .addFields({ name: 'Created At', value: ``, inline: false }) + .addFields({ name: 'Joined At', value: ``, inline: true }) + .addFields({ name: 'Bot', value: `${user.bot}`, inline: false }) + .addFields({ name: 'Roles', value: `${member.roles.cache.map(r => r).join(' ')}`, inline: false }) + .setFooter({ + iconURL: interaction.client.user.displayAvatarURL({ dynamic: true }), + text: interaction.client.user.tag + }) + .setTimestamp(Date.now()) + .setAuthor({ + name: interaction.user.tag, + iconURL: interaction.user.displayAvatarURL({ dynamic: true }) + }); + await interaction.reply({ + embeds: [embed] + }) + } +}; diff --git a/src/commands/userContext/getAvatar.js b/src/commands/userContext/getAvatar.js new file mode 100644 index 0000000..96bf447 --- /dev/null +++ b/src/commands/userContext/getAvatar.js @@ -0,0 +1,13 @@ +const { ContextMenuCommandBuilder, ApplicationCommandType } = require('discord.js'); + +module.exports = { + data: new ContextMenuCommandBuilder() + .setName('Avatar') + .setType(ApplicationCommandType.User), + async execute(interaction) { + const user = interaction.options.getUser('user'); + await interaction.reply({ + content: user.displayAvatarURL({ dynamic: true }) + }); + } +}; diff --git a/src/commands/userContext/userinfo.js b/src/commands/userContext/userinfo.js new file mode 100644 index 0000000..5ceb0b4 --- /dev/null +++ b/src/commands/userContext/userinfo.js @@ -0,0 +1,32 @@ +const { ContextMenuCommandBuilder, ApplicationCommandType, EmbedBuilder } = require('discord.js'); + +module.exports = { + data: new ContextMenuCommandBuilder() + .setName('User Info') + .setType(ApplicationCommandType.User), + async execute(interaction) { + const user = interaction.options.getUser('user'); + const member = await interaction.guild.members.fetch(user.id); + const embed = new EmbedBuilder() + .setTitle(`${user.username}#${user.discriminator}`) + .setDescription(`ID: ${user.id}`) + .setColor([255, 255, 255]) + .setThumbnail(user.displayAvatarURL({ dynamic: true })) + .addFields({ name: 'Created At', value: ``, inline: false }) + .addFields({ name: 'Joined At', value: ``, inline: true }) + .addFields({ name: 'Bot', value: `${user.bot}`, inline: false }) + .addFields({ name: 'Roles', value: `${member.roles.cache.map(r => r).join(' ')}`, inline: false }) + .setFooter({ + iconURL: user.displayAvatarURL({ dynamic: true }), + text: user.tag + }) + .setTimestamp(Date.now()) + .setAuthor({ + name: user.tag, + iconURL: user.displayAvatarURL({ dynamic: true }) + }); + await interaction.reply({ + embeds: [embed] + }); + } +}; \ No newline at end of file diff --git a/src/components/buttons/github-btn.js b/src/components/buttons/github-btn.js new file mode 100644 index 0000000..c77582d --- /dev/null +++ b/src/components/buttons/github-btn.js @@ -0,0 +1,12 @@ +module.exports = { + data: { + name: 'github', + description: 'Github button', + type: 2 + }, + async execute(interaction) { + await interaction.reply({ + content: 'https://github.com/isabelroses', + }); + } +} diff --git a/src/events/client/interactionCreate.js b/src/events/client/interactionCreate.js new file mode 100644 index 0000000..57a35f9 --- /dev/null +++ b/src/events/client/interactionCreate.js @@ -0,0 +1,39 @@ +module.exports = { + name: 'interactionCreate', + async execute(interaction, client) { + if (interaction.isChatInputCommand()) { + const { commands } = client; + const { commandName } = interaction; + const command = commands.get(commandName); + if (!command) return; + try { + await command.execute(interaction, client); + } catch (error) { + console.error(error); + await interaction.reply({ content: 'There was an error while executing this command!', ephemeral: true }); + } + } else if (interaction.isButton()) { + const { buttons } = client; + const { customId } = interaction; + const button = buttons.get(customId); + if (!button) return; + try { + await button.execute(interaction, client); + } catch (error) { + console.error(error); + await interaction.reply({ content: 'There was an error while executing this button!', ephemeral: true }); + } + } else if (interaction.isContextMenuCommand()) { + const { commands } = client; + const { commandName } = interaction; + const contextCommand = commands.get(commandName); + if (!contextCommand) return; + try { + await contextCommand.execute(interaction, client); + } catch (error) { + console.error(error); + await interaction.reply({ content: 'There was an error while executing this context menu command!', ephemeral: true }); + } + } + } +}; \ No newline at end of file diff --git a/src/events/client/ready.js b/src/events/client/ready.js new file mode 100644 index 0000000..ad3a995 --- /dev/null +++ b/src/events/client/ready.js @@ -0,0 +1,9 @@ +module.exports = { + name: 'ready', + once: true, + execute(client) { + console.log(`Logged in as ${client.user.tag}!`); + client.handleCommands(); + client.pickPresence(); + } +}; \ No newline at end of file diff --git a/src/functions/handlers/commands.js b/src/functions/handlers/commands.js new file mode 100644 index 0000000..a68570c --- /dev/null +++ b/src/functions/handlers/commands.js @@ -0,0 +1,30 @@ +const { REST } = require('@discordjs/rest'); +const { Routes } = require('discord-api-types/v9'); +const fs = require('fs'); + +module.exports = (client) => { + client.handleCommands = async () => { + const commandFolders = fs.readdirSync('./src/commands'); + for (const folder of commandFolders) { + const commandFiles = fs.readdirSync(`./src/commands/${folder}`).filter(file => file.endsWith('.js')); + const { commands, commandArray } = client; + for (const file of commandFiles) { + const command = require(`../../commands/${folder}/${file}`); + commands.set(command.data.name, command); + commandArray.push(command.data.toJSON()); + } + } + const guild_ids = client.guilds.cache.map(guild => guild.id); + const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN); + try { + console.log('Started refreshing application (/) commands.'); + for (const guildId of guild_ids) { + await rest.put(Routes.applicationGuildCommands(process.env.CLIENT_ID, guildId), + { body: client.commandArray } + ).then(() => console.log('Successfully updated commands for guild ' + guildId)).catch(console.error); + } + } catch (error) { + console.error(error); + } + } +} diff --git a/src/functions/handlers/components.js b/src/functions/handlers/components.js new file mode 100644 index 0000000..6135463 --- /dev/null +++ b/src/functions/handlers/components.js @@ -0,0 +1,21 @@ +const { readdirSync } = require('fs'); + +module.exports = (client) => { + client.handleComponents = async () => { + const componentFolders = readdirSync('./src/components'); + for (const folder of componentFolders) { + const componentFiles = readdirSync(`./src/components/${folder}`).filter(file => file.endsWith('.js')); + const { buttons } = client; + switch (folder) { + case 'buttons': + for (const file of componentFiles) { + const button = require(`../../components/${folder}/${file}`); + buttons.set(button.data.name, button); + } + break; + default: + break; + } + } + } +} \ No newline at end of file diff --git a/src/functions/handlers/events.js b/src/functions/handlers/events.js new file mode 100644 index 0000000..b3223dd --- /dev/null +++ b/src/functions/handlers/events.js @@ -0,0 +1,22 @@ +const fs = require('fs'); + +module.exports = (client) => { + client.handleEvents = async () => { + const eventFolders = fs.readdirSync('./src/events'); + for (const folder of eventFolders) { + const eventFiles = fs.readdirSync(`./src/events/${folder}`).filter((file) => file.endsWith('.js')); + switch (folder) { + case "client": + for (const file of eventFiles) { + const event = require(`../../events/${folder}/${file}`); + if (event.once) client.once(event.name, (...args) => event.execute(...args, client)); + else client.on(event.name, (...args) => event.execute(...args, client)); + } + break; + + default: + break; + } + } + } +} \ No newline at end of file diff --git a/src/functions/tools/pickPresence.js b/src/functions/tools/pickPresence.js new file mode 100644 index 0000000..2afdfd6 --- /dev/null +++ b/src/functions/tools/pickPresence.js @@ -0,0 +1,21 @@ +const { ActivityType } = require('discord.js'); + +module.exports = (client) => { + client.pickPresence = async () => { + const options = [ + { text: 'with Slash Commands', type: ActivityType.Playing, url: null, status: 'online' }, + { text: '/help', type: ActivityType.Watching, url: null, status: 'online' }, + ]; + const option = Math.floor(Math.random() * options.length); + + client.user.setPresence({ + activities: [{ + name: options[option].text, + type: options[option].type, + url: options[option].url, + }], + status: options[option].status, + }); + console.log(`Presence set to ${options[option].text}`); + } +}