├── .eslintrc.js ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── ---bug-report.md │ └── ---feature-request.md └── workflows │ ├── build-bot.yml │ └── deploy-bot.yml ├── .gitignore ├── .prettierrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── Makefile ├── README.md ├── app ├── commands │ ├── Configuration │ │ └── setlang.js │ ├── Info │ │ ├── help.js │ │ ├── invite.js │ │ ├── ping.js │ │ ├── stats.js │ │ ├── support.js │ │ └── vote.js │ ├── Sound │ │ └── playsound.js │ ├── Test │ │ ├── emitgd.js │ │ └── emitgr.js │ └── Text │ │ └── trickortreat.js ├── config │ └── config.example.json ├── core.js ├── db │ ├── .gitkeep │ ├── servers.json │ └── trickortreats.json ├── events │ ├── guildCreate.js │ ├── guildDelete.js │ ├── message.js │ └── ready.js ├── handlers │ ├── command.js │ └── event.js ├── images │ ├── spookyBot-emoji.png │ └── spookyBot.png ├── lang │ ├── ar.js │ ├── ca.js │ ├── de.js │ ├── el.js │ ├── en.js │ ├── es.js │ ├── fr.js │ ├── gr.js │ ├── hi.js │ ├── nl.js │ ├── pt.js │ ├── sv.js │ ├── tr.js │ └── zh.js ├── models │ ├── servers.js │ └── trickortreats.js ├── sounds │ ├── batR.wav │ ├── boo_laughR.wav │ ├── chainsawR.wav │ ├── creaky_doorR.wav │ ├── entrance_mixR.wav │ ├── ghostR.wav │ ├── howlin_wolfR.wav │ ├── lab2XrcR.wav │ ├── mnstrX.wav │ ├── noreturnR.wav │ ├── ogreR.wav │ ├── spooky_skeleton.mp3 │ ├── thunderR.wav │ ├── way_scaryR.wav │ ├── welcomeR.wav │ ├── windR.wav │ └── wrong_doorR.wav └── utils │ ├── languageCode.js │ └── reactMessage.js ├── docker-compose.dev.yml ├── docker └── spooky-node │ ├── DockerfileDev │ └── DockerfileProd ├── nodemon.json └── package.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | es6: true, 7 | }, 8 | extends: ['prettier'], 9 | plugins: ['prettier'], 10 | rules: { 11 | 'prettier/prettier': 'error', 12 | }, 13 | parserOptions: { 14 | ecmaVersion: 8, 15 | }, 16 | overrides: [ 17 | { 18 | files: ['app/lang/*.js'], 19 | rules: { 20 | 'require-jsdoc': 'off', 21 | }, 22 | }, 23 | ], 24 | } 25 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: LucasAlt 4 | ko_fi: lucasalt 5 | custom: ["https://www.buymeacoffee.com/lucasalt"] 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug Report" 3 | about: "If something isn't working as expected \U0001F914" 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | ## Bug Report 10 | 11 | **Current Behavior** 12 | A clear and concise description of the behavior. 13 | 14 | **Expected behavior/code** 15 | A clear and concise description of what you expected to happen (or code). 16 | 17 | **Possible Solution** 18 | 19 | 20 | **Additional context/Screenshots** 21 | Add any other context about the problem here. If applicable, add screenshots to help explain. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680 Feature Request" 3 | about: "I have a suggestion (and may want to implement it \U0001F642)!" 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | --- 8 | 9 | ## Feature Request 10 | 11 | **Is your feature request related to a problem? Please describe.** 12 | A clear and concise description of what the problem is. Ex. I have an issue when [...] 13 | 14 | **Describe the solution you'd like** 15 | A clear and concise description of what you want to happen. Add any considered drawbacks. 16 | 17 | **Describe alternatives you've considered** 18 | A clear and concise description of any alternative solutions or features you've considered. 19 | 20 | **Teachability, Documentation, Adoption, Migration Strategy** 21 | If you can, explain how users will be able to use this and possibly write out a version the docs. 22 | Maybe a screenshot or design? -------------------------------------------------------------------------------- /.github/workflows/build-bot.yml: -------------------------------------------------------------------------------- 1 | name: Build Workflow 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | job_one: 8 | name: Build and push docker images 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Build docker-image 13 | env: 14 | DOCKER_USER: ${{ secrets.DOCKER_USER }} 15 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 16 | run: | 17 | docker login -u $DOCKER_USER -p $DOCKER_PASSWORD 18 | docker build -f ./docker/spooky-node/DockerfileProd --build-arg NODE_VERSION=12.18.2 -t spookybot/spookybot:latest -t spookybot/spookybot:${{github.run_number}} . 19 | docker push spookybot/spookybot:${{github.run_number}} 20 | docker push spookybot/spookybot:latest 21 | docker logout 22 | 23 | 24 | -------------------------------------------------------------------------------- /.github/workflows/deploy-bot.yml: -------------------------------------------------------------------------------- 1 | name: Deployment Workflow 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | tags: 6 | description: 'Tag' 7 | jobs: 8 | deploy_prod_bot: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: appleboy/ssh-action@master 12 | name: deploy to prod 13 | with: 14 | host: ${{ secrets.SSH_IP }} 15 | port: ${{ secrets.SSH_PORT }} 16 | username: spookybot 17 | key: ${{ secrets.SSH_KEY }} 18 | script: | 19 | docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }} 20 | docker pull spookybot/spookybot:latest 21 | docker-compose -f /home/spookybot/docker-compose.yml down -v 22 | docker-compose -f /home/spookybot/docker-compose.yml up -d 23 | docker logout 24 | 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Dependency directories 10 | node_modules/ 11 | jspm_packages/ 12 | 13 | # Optional npm cache directory 14 | .npm 15 | 16 | # Optional eslint cache 17 | .eslintcache 18 | .eslintrc.js 19 | 20 | # Yarn Integrity file 21 | .yarn-integrity 22 | 23 | # config file 24 | app/config/config.json 25 | # IDE 26 | .idea 27 | *.iml 28 | 29 | 30 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": true, 7 | "trailingComma": "es5", 8 | "bracketSpacing": true, 9 | "arrowParens": "always", 10 | "endOfLine": "lf" 11 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at contact@lucasalt.fr. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to contribute to SpookyBot 2 | 3 | #### **Did you find a bug?** 4 | 5 | * **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/LucasCtrl/spookyBot/issues). 6 | 7 | * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/LucasCtrl/spookyBot/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring. 8 | 9 | #### **Did you write a patch that fixes a bug?** 10 | 11 | * Open a new GitHub pull request with the patch. 12 | 13 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 14 | 15 | #### **Did you fix whitespace, format code, or make a purely cosmetic patch?** 16 | 17 | Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of the bot will generally not be accepted. 18 | 19 | #### **Do you intend to add a new feature or change an existing one?** 20 | 21 | * Suggest your change in a [GitHub issue](https://github.com/LucasCtrl/spookyBot/issues) and start writing code. 22 | 23 | #### **Do you have questions about the source code or the bot?** 24 | 25 | * Ask any question about SpookyBot on our [Discord server](https://discord.gg/nEDcagb). 26 | 27 | 28 | Thanks! :heart: :heart: :heart: 29 | 30 | LucasAlt -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 LucasAlt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DOCKERCOMPOSE_DEV=-f docker-compose.dev.yml 2 | 3 | 4 | .PHONY: build_dev_image 5 | build_dev_image: 6 | docker build -f ./docker/spooky-node/DockerfileDev -t spookybot:dev . 7 | 8 | .PHONY: startup_dev 9 | startup_dev: 10 | docker-compose ${DOCKERCOMPOSE_DEV} up -d 11 | 12 | .PHONY: stop_dev 13 | stop_dev: 14 | docker-compose ${DOCKERCOMPOSE_DEV} down -v 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SpookyBot 2 | 🎃 *A spooky Discord bot* 3 | 4 | [![release](https://img.shields.io/github/release/LucasCtrl/spookyBot.svg?style=flat-square&logo=github&logoColor=fafafa&colorA=191b25&colorB=32cb8b)](https://github.com/LucasCtrl/spookyBot/releases/latest) 5 | [![issues](https://img.shields.io/github/issues/LucasCtrl/spookyBot.svg?style=flat-square&colorA=191b25)](https://github.com/LucasCtrl/spookyBot/issues) 6 | [![stars](https://img.shields.io/github/stars/LucasCtrl/spookyBot.svg?style=flat-square&colorA=191b25)](https://github.com/LucasCtrl/spookyBot/stargazers) 7 | [![forks](https://img.shields.io/github/forks/LucasCtrl/spookyBot.svg?style=flat-square&colorA=191b25)](https://github.com/LucasCtrl/spookyBot/network) 8 | 9 | This project is convenient for people who want to get into open source and contribute to different projects especially during the Hacktoberfest. 10 | 11 | *Don't hesitate to ask me for help on my [Discord server](https://discord.gg/nEDcagb), I would help you with great pleasure!* 12 | 13 | ## 🤖 Add the bot on your server 14 | 15 | You just need to click on [this link](https://discord.com/oauth2/authorize?client_id=761568927188123669&scope=bot&permissions=1141124160) and validate the form without changing any permission. 16 | 17 | ## 🌐 Adding a language 18 | 19 | You can add languages to the robot so that it is translated and accessible to everyone! 20 | 21 | To do this, nothing could be simpler, just copy the file `./app/lang/en.js` then rename it following the [ISO 639-1 nomenclature](http://www.mathguide.de/info/tools/languagecode.html). 22 | Then you just need to modify the file as you wish. For the translation to be set up on the robot, do not hesitate to open a pull request by [following this guide](https://github.com/LucasCtrl/spookyBot/blob/main/README.md#-contributing). 23 | 24 | To react to a word, you need two elements in the translation file: the word and the emoji with which it will react. 25 | 26 | ```json 27 | { 28 | "name": "halloween", 29 | "emoji": "🎃" 30 | } 31 | ``` 32 | 33 | You can see that the `emoji` element is an emoji, but you can also use a custom emoji. For that, I strongly advise you to [read this guide](https://discordjs.guide/popular-topics/reactions.html#custom-emojis). 34 | 35 | ## 💻 Testing locally 36 | 1. Create a bot [on the Discord developer portal](https://discord.com/developers/applications), 37 | 2. Create a webhook on your own discord server [by following this tutorial](https://docs.gitlab.com/ee/user/project/integrations/discord_notifications.html), 38 | 3. Copy the `./app/config/config.example.json` from the project to `./app/config/config.json` and fill in the gaps with the information from the bot and the webhook. The first token is on the bot page accessed from the side of the Discord Developer Portal, and the webook information is found on the page when you navigate to the webhook url, 39 | 4. Invite your dev bot to your server by [following this url](https://discord.com/oauth2/authorize?client_id=761568927188123669&scope=bot&permissions=1141124160), replacing the client id with your bot's client id (found on it's general information page), and the permissions with the Permission Integer created in the Developer Portal as you select permissions for your bot, 40 | 5. Once these steps are setup, simply run `make startup_dev` from the terminal in the root directory of the repo, 41 | 5.1 If you want to install node modules you could just add it into your local package.json and run the `make build_dev_image` after that you need to recreate the container. 42 | 6. Test the bot is connected by running `help` to get a list of commands, and then initialize the DB by running `emitgc`. It should then respond with "Join with <#> users, 43 | 7. Test that the bot reacts to comments by typing one of the words in `lang/.js`. The bot should respond with an emoji! 44 | 45 | ## 👤 Author 46 | 47 | **LucasAlt** 48 | * Website: https://www.lucasalt.fr 49 | * Twitter: [@LucasCtrlAlt](https://twitter.com/LucasCtrlAlt) 50 | * GitHub: [@LucasCtrl](https://github.com/LucasCtrl) 51 | 52 | ## 🙏 Thanks 53 | * [**@ALMerrill**](https://github.com/ALMerrill) - Translation (es, de), code, documentation 54 | * [**@marc2332**](https://github.com/marc2332) - Translation (es, ca) 55 | * [**@tmetten**](https://github.com/tmetten) - Translation (nl) 56 | * [**@dragonDScript**](https://github.com/dragonDScript) - Translation (ca) 57 | * [**@Pervolarakis**](https://github.com/Pervolarakis) - Translation (gr) 58 | * [And many more!](https://github.com/LucasCtrl/spookyBot/graphs/contributors) 59 | 60 | ## 🤝 Contributing 61 | 62 | Before contributing to this project, make sure you have read the [contribution guidelines](https://github.com/LucasCtrl/spookyBot/blob/main/CONTRIBUTING.md)! 63 | 64 | 1. Fork it (https://github.com/LucasCtrl/spookyBot/fork) 65 | 2. Create your feature branch (`git checkout -b feature/fooBar`) 66 | 3. Commit your changes (`git commit -am 'Add some fooBar'`) 67 | 4. Push to the branch (`git push origin feature/fooBar`) 68 | 5. Create a new Pull Request 69 | 70 | ## Show your support 71 | 72 | Give a ⭐️ if you like this project! 73 | 74 | 75 | Buy Me a Coffee at ko-fi.com 76 | 77 | 78 | ## 📝 License 79 | 80 | This project is open source and available under the [MIT](https://github.com/LucasCtrl/spookyBot/blob/master/LICENSE) 81 | -------------------------------------------------------------------------------- /app/commands/Configuration/setlang.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../../config/config.json') 3 | 4 | const { readdirSync } = require('fs') 5 | const { resolve } = require('path') 6 | 7 | const { changeLang } = require('../../models/servers') 8 | 9 | const ISOCode = require('../../utils/languageCode') 10 | 11 | module.exports = { 12 | config: { 13 | command: 'setlang', 14 | name: 'Set bot language', 15 | description: 'Change the default bot language', 16 | usage: `${prefix}setlang `, 17 | displayHelp: true, 18 | permissionNeeded: 'ADMINISTRATOR', 19 | }, 20 | 21 | run: async (bot, message, args) => { 22 | // Get all available language 23 | let availableLang = [] 24 | readdirSync(resolve(__dirname, `../../lang/`)) 25 | .filter((d) => d.endsWith('.js')) 26 | .forEach((file) => { 27 | availableLang.push(file.slice(0, -3)) 28 | }) 29 | 30 | // Check if the language exist 31 | const newLang = availableLang.find((lang) => lang == args[0]) 32 | 33 | if (newLang != undefined) { 34 | // The language exist 35 | const embed = new MessageEmbed().setColor(colors.primary).setDescription(`Language set to: **${args[0]}**`) 36 | message.channel.send(embed).then((m) => { 37 | setTimeout(() => { 38 | m.delete() 39 | }, 5000) 40 | }) 41 | 42 | changeLang(message.guild.id, args[0]) 43 | } else { 44 | // The language doesn't exist 45 | let messageContent = [ 46 | 'The requested language does not exist, please choose a language from this list: (the bold part)', 47 | ] 48 | availableLang.forEach((lang) => messageContent.push(`- **${lang}**: ${ISOCode.find((l) => l.code == lang).name}`)) 49 | 50 | const embed = new MessageEmbed() 51 | .setColor(colors.primary) 52 | .setDescription(messageContent) 53 | .setFooter( 54 | "If you can't find your language, don't hesitate to contact us by using the command boo!support | This message will be deleted automatically" 55 | ) 56 | 57 | message.channel.send(embed).then((m) => { 58 | setTimeout(() => { 59 | m.delete() 60 | }, 20000) 61 | }) 62 | } 63 | }, 64 | } 65 | -------------------------------------------------------------------------------- /app/commands/Info/help.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../../config/config.json') 3 | const { version } = require('../../../package.json') 4 | 5 | module.exports = { 6 | config: { 7 | name: 'Help', 8 | usage: `${prefix}help`, 9 | description: 'Display this menu', 10 | command: 'help', 11 | aliases: ['h', 'commands', 'info'], 12 | displayHelp: true, 13 | }, 14 | 15 | run: async (bot, message, args) => { 16 | let embed = await new MessageEmbed() 17 | .setColor(colors.primary) 18 | .setFooter(`Requested by ${message.author.username}`, message.author.avatarURL({ dynamic: true })) 19 | .addField('\u200b', '📍 **INFORMATIONS**', false) 20 | .addField('Support', 'https://discord.gg/nEDcagb', true) 21 | .addField('Source code', 'https://github.com/LucasCtrl/spookyBot', true) 22 | .addField('🤖 Bot version', version, false) 23 | .addField('\u200b', '📍 **COMMANDS LIST**', false) 24 | 25 | bot.commands.forEach((c) => { 26 | if (c.config.displayHelp) { 27 | embed.addField(c.config.name, `${c.config.description}\n**Usage: **${c.config.usage}`, false) 28 | } 29 | }) 30 | 31 | message.author.send(embed) 32 | }, 33 | } 34 | -------------------------------------------------------------------------------- /app/commands/Info/invite.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../../config/config.json') 3 | 4 | module.exports = { 5 | config: { 6 | command: 'invite', 7 | name: 'Invite', 8 | description: 'Get an invitation link for inviting the bot on your server', 9 | usage: `${prefix}invite`, 10 | displayHelp: true, 11 | }, 12 | 13 | run: async (bot, message, args) => { 14 | const embed = new MessageEmbed() 15 | .setColor(colors.primary) 16 | .setAuthor('Invitation link', bot.user.avatarURL()) 17 | .setDescription( 18 | 'You can click on the following link for adding the bot on your server: [https://discord.com/oauth2/authorize?client_id=761568927188123669&scope=bot&permissions=1141124160](https://discord.com/oauth2/authorize?client_id=761568927188123669&scope=bot&permissions=1141124160)' 19 | ) 20 | 21 | message.channel.send(embed) 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /app/commands/Info/ping.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../../config/config.json') 3 | 4 | module.exports = { 5 | config: { 6 | command: 'ping', 7 | name: 'Ping', 8 | description: 'Average heart rate of the robot', 9 | usage: `${prefix}ping`, 10 | displayHelp: false, 11 | }, 12 | 13 | run: async (bot, message, args) => { 14 | const beforePing = new MessageEmbed().setColor(colors.primary).setDescription('Pinging...') 15 | 16 | message.channel.send(beforePing).then((m) => { 17 | let ping = m.createdTimestamp - message.createdTimestamp 18 | 19 | const afterPing = new MessageEmbed() 20 | .setColor(colors.primary) 21 | .setDescription(`Pong! :ping_pong:\nBot Latency: \`${ping}ms\`, API Latency: \`${Math.round(bot.ws.ping)}ms\``) 22 | 23 | m.edit(afterPing) 24 | }) 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /app/commands/Info/stats.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../../config/config.json') 3 | 4 | module.exports = { 5 | config: { 6 | command: 'stats', 7 | name: 'Stat', 8 | description: 'Give you some statistics about the bot', 9 | usage: `${prefix}stats`, 10 | displayHelp: true, 11 | }, 12 | 13 | run: async (bot, message, args) => { 14 | const memoryStats = process.memoryUsage() 15 | 16 | const embed = new MessageEmbed() 17 | .setColor(colors.primary) 18 | .setAuthor(`Stats - ${bot.user.username}`, bot.user.avatarURL({ dynamic: true })) 19 | .addField('Number of servers ¬', bot.guilds.cache.size.toLocaleString(), true) 20 | .addField( 21 | 'Number of users ¬', 22 | bot.guilds.cache.reduce((mem, g) => (mem += g.memberCount), 0), 23 | true 24 | ) 25 | .addField('Number of emojis ¬', bot.emojis.cache.size, true) 26 | .addField('Number of channels ¬', bot.channels.cache.size, true) 27 | .addField('Memory usage ¬', `${Math.ceil(memoryStats.heapUsed / 1048576)} Mo`, true) 28 | .setFooter(`Requested by ${message.author.username}`, message.author.avatarURL({ dynamic: true })) 29 | 30 | message.channel.send(embed) 31 | }, 32 | } 33 | -------------------------------------------------------------------------------- /app/commands/Info/support.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../../config/config.json') 3 | 4 | module.exports = { 5 | config: { 6 | command: 'support', 7 | name: 'Support', 8 | description: 'Get the support server invitation link', 9 | usage: `${prefix}support`, 10 | displayHelp: true, 11 | }, 12 | 13 | run: async (bot, message, args) => { 14 | const embed = new MessageEmbed() 15 | .setColor(colors.primary) 16 | .setAuthor('Support server', bot.user.avatarURL()) 17 | .setDescription( 18 | 'You can click on the following link for joining the support server: [https://discord.gg/nEDcagb](https://discord.gg/nEDcagb)' 19 | ) 20 | 21 | message.channel.send(embed) 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /app/commands/Info/vote.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../../config/config.json') 3 | 4 | module.exports = { 5 | config: { 6 | command: 'vote', 7 | name: 'Vote', 8 | description: 'Vote for the bot', 9 | usage: `${prefix}vote`, 10 | displayHelp: true, 11 | }, 12 | 13 | run: async (bot, message, args) => { 14 | const embed = new MessageEmbed() 15 | .setColor(colors.primary) 16 | .setAuthor('Support server', bot.user.avatarURL()) 17 | .setDescription( 18 | 'You can vote for the bot by clicking on the following link: [https://discordbotlist.com/bots/spookybot/upvote](https://discordbotlist.com/bots/spookybot/upvote)' 19 | ) 20 | 21 | message.channel.send(embed) 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /app/commands/Sound/playsound.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix } = require('../../config/config.json') 3 | const { readdirSync } = require('fs') 4 | const { resolve } = require('path') 5 | 6 | module.exports = { 7 | config: { 8 | name: 'Boo Sound', 9 | usage: `${prefix}booh`, 10 | description: 'Joins your voice channel and scares you', 11 | command: 'booh', 12 | aliases: ['buh', 'scare'], 13 | displayHelp: true, 14 | }, 15 | 16 | run: async (bot, message, args) => { 17 | if (message.member.voice.channel) { 18 | let soundPath = __dirname + `/../../sounds/` 19 | const connection = await message.member.voice.channel.join() 20 | const sounds = Array.from(readdirSync(resolve(__dirname, `../../sounds/`))) 21 | let playable = soundPath + sounds[Math.floor(Math.random() * sounds.length)] 22 | 23 | const dispatcher = connection.play(playable, { 24 | volume: 0.5, 25 | }) 26 | 27 | dispatcher.on('finish', () => { 28 | connection.voice.channel.leave() 29 | }) 30 | } else { 31 | const embed = new MessageEmbed() 32 | .setTitle('How can I scare your companions without you beeing present in the voice channel?') 33 | .setColor(colors.primary) 34 | 35 | message.channel.send(embed).then((m) => { 36 | setTimeout(() => { 37 | m.delete() 38 | }, 5000) 39 | }) 40 | } 41 | }, 42 | } 43 | -------------------------------------------------------------------------------- /app/commands/Test/emitgd.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | command: 'emitgc', 4 | description: 'guildCreate event', 5 | }, 6 | 7 | run: async (bot, message, args) => { 8 | bot.emit('guildCreate', message.guild) 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /app/commands/Test/emitgr.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | config: { 3 | command: 'emitgd', 4 | description: 'guildDelete event', 5 | }, 6 | 7 | run: async (bot, message, args) => { 8 | bot.emit('guildDelete', message.guild) 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /app/commands/Text/trickortreat.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../../config/config.json') 3 | 4 | const { treat, trick, createTrickOrTreat, getTrickOrTreat } = require('../../models/trickortreats') 5 | 6 | const isToday = (someDate) => { 7 | const today = new Date() 8 | const currentDate = new Date(Date.parse(someDate)) 9 | 10 | return ( 11 | currentDate.getDate() == today.getDate() && 12 | currentDate.getMonth() == today.getMonth() && 13 | currentDate.getFullYear() == today.getFullYear() 14 | ) 15 | } 16 | 17 | module.exports = { 18 | config: { 19 | name: 'Trick or Treat', 20 | usage: `${prefix}trickortreat`, 21 | description: 'Gives you candy or scares you 😈', 22 | command: 'trickortreat', 23 | aliases: ['tot'], 24 | displayHelp: true, 25 | }, 26 | 27 | run: async (bot, message, args) => { 28 | let trickOrTreat = await getTrickOrTreat(message.author.id) 29 | 30 | if (!trickOrTreat) { 31 | await createTrickOrTreat(message.author.id) 32 | trickOrTreat = await getTrickOrTreat(message.author.id) 33 | } 34 | 35 | if (!trickOrTreat.lastPlayed || !isToday(trickOrTreat.lastPlayed)) { 36 | if (Math.random() >= 0.5) { 37 | trickOrTreat = await trick(message.author.id) 38 | 39 | let embed = await new MessageEmbed() 40 | .setTitle(':smiling_imp: Oh no!, You have been tricked!') 41 | .setColor(colors.info) 42 | .setDescription('Better luck tomorrow!') 43 | .addField(':candy: Candys', trickOrTreat.treats, true) 44 | .addField(':smiling_imp: Tricks', trickOrTreat.tricks, true) 45 | .setFooter(message.author.username, message.author.avatarURL({ dynamic: true })) 46 | .setTimestamp(new Date()) 47 | 48 | await message.channel.send(embed) 49 | } else { 50 | trickOrTreat = await treat(message.author.id) 51 | 52 | let embed = await new MessageEmbed() 53 | .setTitle(':candy: Sweet, sweet candy!') 54 | .setColor(colors.error) 55 | .setDescription('There will be more candy up for grabs tomorrow!') 56 | .addField(':candy: Candys', trickOrTreat.treats, true) 57 | .addField(':smiling_imp: Tricks', trickOrTreat.tricks, true) 58 | .setFooter(message.author.username, message.author.avatarURL({ dynamic: true })) 59 | .setTimestamp(new Date()) 60 | 61 | await message.channel.send(embed) 62 | } 63 | } else { 64 | const embed = new MessageEmbed() 65 | .setTitle('It looks like you have already played today.') 66 | .setColor(colors.primary) 67 | .setDescription('There will be more candy up for grabs tomorrow!') 68 | .addField(':candy: Candys', trickOrTreat.treats, true) 69 | .addField(':smiling_imp: Tricks', trickOrTreat.tricks, true) 70 | .setFooter(message.author.username, message.author.avatarURL({ dynamic: true })) 71 | .setTimestamp(new Date()) 72 | 73 | message.channel.send(embed) 74 | } 75 | }, 76 | } 77 | -------------------------------------------------------------------------------- /app/config/config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "", 3 | "prefix": "boo!", 4 | "webhook": { 5 | "id": "", 6 | "token": "" 7 | }, 8 | "colors": { 9 | "primary": "#FF6403", 10 | "success": "#2ECC71", 11 | "error": "#E74C3C", 12 | "info": "#7C5398" 13 | } 14 | } -------------------------------------------------------------------------------- /app/core.js: -------------------------------------------------------------------------------- 1 | const { Client, Collection, WebhookClient } = require('discord.js') 2 | 3 | const { token, webhook } = require('./config/config.json') 4 | 5 | const bot = new Client() 6 | 7 | // -------------------- Webhooks -------------------- 8 | 9 | const logsWebhook = new WebhookClient(webhook.id, webhook.token) 10 | 11 | // -------------------- Commands/Events handling -------------------- 12 | 13 | const cmds = ['aliases', 'commands'] 14 | const handlers = ['command', 'event'] 15 | 16 | cmds.forEach((x) => (bot[x] = new Collection())) 17 | handlers.forEach((x) => require(`./handlers/${x}`)(bot, logsWebhook)) 18 | 19 | // -------------------- Login -------------------- 20 | 21 | bot.login(token) 22 | -------------------------------------------------------------------------------- /app/db/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/db/.gitkeep -------------------------------------------------------------------------------- /app/db/servers.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers": [] 3 | } -------------------------------------------------------------------------------- /app/db/trickortreats.json: -------------------------------------------------------------------------------- 1 | { 2 | "trickortreats": [ 3 | { 4 | "userId": "306856370454396928", 5 | "tricks": 0, 6 | "treats": 0, 7 | "lastPlayed": "2020-10-06T22:55:33.107Z" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /app/events/guildCreate.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { colors } = require('../config/config.json') 3 | 4 | const { createGuild } = require('../models/servers') 5 | 6 | module.exports = (bot, webhook, guild) => { 7 | const embed = new MessageEmbed() 8 | .setColor(colors.success) 9 | .setTitle(`Join **${guild.name}** with ${guild.memberCount} users`) 10 | 11 | webhook.send(embed) 12 | console.log(`Join ${guild.name} with ${guild.memberCount} users`) 13 | 14 | createGuild(guild.id) 15 | } 16 | -------------------------------------------------------------------------------- /app/events/guildDelete.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { colors } = require('../config/config.json') 3 | 4 | const { deleteGuild } = require('../models/servers') 5 | 6 | module.exports = (bot, webhook, guild) => { 7 | const embed = new MessageEmbed() 8 | .setColor(colors.error) 9 | .setTitle(`Leave **${guild.name}** with ${guild.memberCount} users`) 10 | 11 | webhook.send(embed) 12 | console.log(`Leave ${guild.name} with ${guild.memberCount} users`) 13 | 14 | deleteGuild(guild.id) 15 | } 16 | -------------------------------------------------------------------------------- /app/events/message.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { prefix, colors } = require('../config/config.json') 3 | 4 | const reactMessage = require('../utils/reactMessage') 5 | 6 | module.exports = async (bot, webhook, message) => { 7 | if (message.author.bot) return // Ignore all bots 8 | if (message.author.id === bot.user.id) return // Ignore bot itself 9 | if (message.channel.type === 'dm') return // Ignore private messages 10 | 11 | // -------------------- Message with prefix -------------------- 12 | 13 | if (message.content.startsWith(prefix)) { 14 | // Our standard argument/command name definition. 15 | const args = message.content.slice(prefix.length).trim().split(/ +/g) 16 | const command = args.shift().toLowerCase() 17 | 18 | // Grab the command data from the client Collection 19 | const cmd = bot.commands.get(command) || bot.commands.get(bot.aliases.get(command)) 20 | 21 | if (!cmd) return // If that command doesn't exist, silently exit and do nothing 22 | 23 | // -------------------- Private logs -------------------- 24 | 25 | const privateEmbed = new MessageEmbed() 26 | .setColor(colors.primary) 27 | .setTitle(message.content) 28 | .setFooter(`${message.author.tag} | ${message.guild.name}`, message.guild.iconURL()) 29 | 30 | webhook.send(privateEmbed) 31 | 32 | // -------------------- Command execution -------------------- 33 | 34 | message.delete() 35 | if (!message.member.hasPermission(cmd.config.permissionNeeded)) { 36 | message.reply('Only your server administrator can do this!').then((m) => { 37 | setTimeout(() => { 38 | m.delete() 39 | }, 5000) 40 | }) 41 | return 42 | } 43 | cmd.run(bot, message, args) // Run the command 44 | } else { 45 | // -------------------- Reaction system -------------------- 46 | // console.log(reactMessage) 47 | reactMessage(message.guild.id, message, webhook) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/events/ready.js: -------------------------------------------------------------------------------- 1 | const { prefix } = require('../config/config.json') 2 | 3 | let statusInterval = 0 4 | if (process.env.NODE_ENV === 'dev') { 5 | statusInterval = 5000 6 | } else { 7 | statusInterval = 60000 8 | } 9 | 10 | module.exports = async (bot) => { 11 | console.log(`Ready to serve ${bot.guilds.cache.reduce((mem, g) => (mem += g.memberCount), 0)} users`) 12 | setInterval(function () { 13 | let statuses = [ 14 | `${bot.guilds.cache.reduce((mem, g) => (mem += g.memberCount), 0)} users`, 15 | `${bot.guilds.cache.size} servers`, 16 | `${prefix}help`, 17 | ] 18 | 19 | let status = statuses[Math.floor(Math.random() * statuses.length)] 20 | bot.user.setActivity(status, { type: 'WATCHING' }) 21 | }, statusInterval) 22 | } 23 | -------------------------------------------------------------------------------- /app/handlers/command.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require('fs') 2 | const { resolve } = require('path') 3 | 4 | module.exports = (bot) => { 5 | const load = (dirs) => { 6 | const commands = readdirSync(resolve(__dirname, `../commands/${dirs}/`)).filter((d) => d.endsWith('.js')) 7 | for (let file of commands) { 8 | let cmd = require(`../commands/${dirs}/${file}`) 9 | bot.commands.set(cmd.config.command, cmd) 10 | if (cmd.config.aliases) cmd.config.aliases.forEach((a) => bot.aliases.set(a, cmd.config.command)) 11 | } 12 | } 13 | 14 | const dirs = ['Info', 'Configuration', 'Sound', 'Text'] 15 | 16 | if (process.env.NODE_ENV === 'dev') dirs.push('Test') 17 | 18 | dirs.forEach((x) => load(x)) 19 | } 20 | -------------------------------------------------------------------------------- /app/handlers/event.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require('fs') 2 | const { resolve } = require('path') 3 | 4 | module.exports = (bot, webhook) => { 5 | const events = readdirSync(resolve(__dirname, '../events/')).filter((d) => d.endsWith('.js')) 6 | for (let file of events) { 7 | const evt = require(`../events/${file}`) 8 | let eName = file.split('.')[0] 9 | 10 | bot.on(eName, evt.bind(null, bot, webhook)) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/images/spookyBot-emoji.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/images/spookyBot-emoji.png -------------------------------------------------------------------------------- /app/images/spookyBot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/images/spookyBot.png -------------------------------------------------------------------------------- /app/lang/ar.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'ar', //Arabic 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'مرعب', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: ['حلوى', 'حلويات'], 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: 'شبح', 15 | emoji: '👻', 16 | }, 17 | { 18 | name: 'عيد الرعب', 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: 'مصاص دماء', 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: 'ساحر', 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: 'الاموات الاحياء', 31 | emoji: '🧟', 32 | }, 33 | ], 34 | } -------------------------------------------------------------------------------- /app/lang/ca.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'ca', //Catalan 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'spooky', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: ['caramel', 'dolç'], 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: 'fantasma', 15 | emoji: '👻', 16 | }, 17 | { 18 | name: 'halloween', 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: 'vampir', 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: 'mag', 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: 'zombie', 31 | emoji: '🧟', 32 | }, 33 | ], 34 | } 35 | -------------------------------------------------------------------------------- /app/lang/de.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'de', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: ['spooky', 'gruselig'], 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: ['alien', 'außerirdische', 'außerirdischer'], 11 | emoji: '👽', 12 | }, 13 | { 14 | name: ['alienmonster', 'monster'], 15 | emoji: '👾', 16 | }, 17 | // Coming with Unicode/Emoji 13.0 this year, e.g. with Android 11 18 | // { 19 | // name: ['herz', 'anatomisches herz'], 20 | // emoji: '🫀', 21 | // }, 22 | { 23 | name: ['wütender teufel'], 24 | emoji: '👿', 25 | }, 26 | { 27 | name: ['unruhig', 'besorgt'], 28 | emoji: '😰', 29 | }, 30 | { 31 | name: ['axt'], 32 | emoji: '🪓', 33 | }, 34 | { 35 | name: ['fledermaus'], 36 | emoji: '🦇', 37 | }, 38 | { 39 | name: ['schlagendes herz'], 40 | emoji: '💓', 41 | }, 42 | { 43 | name: ['schwarzes herz'], 44 | emoji: '🖤', 45 | }, 46 | { 47 | name: ['schwarze katze'], 48 | emoji: '🐈‍⬛', 49 | }, 50 | { 51 | name: ['blut'], 52 | emoji: '🩸', 53 | }, 54 | { 55 | name: ['blutstropfen'], 56 | emoji: '🩸', 57 | }, 58 | { 59 | name: ['knochen'], 60 | emoji: '🦴', 61 | }, 62 | { 63 | name: ['gehirn', 'brain'], 64 | emoji: '🧠', 65 | }, 66 | { 67 | name: ['besen'], 68 | emoji: '🧹', 69 | }, 70 | { 71 | name: ['kerze'], 72 | emoji: '🕯', 73 | }, 74 | { 75 | name: ['candy', 'bonbon', 'süßigkeit'], 76 | emoji: '🍬', 77 | }, 78 | { 79 | name: ['ketten'], 80 | emoji: '⛓', 81 | }, 82 | { 83 | name: ['schokoladenriegel', 'schokoriegel'], 84 | emoji: '🍫', 85 | }, 86 | { 87 | name: ['blitz', 'gewitterwolke'], 88 | emoji: '🌩', 89 | }, 90 | { 91 | name: ['clown'], 92 | emoji: '🤡', 93 | }, 94 | { 95 | name: ['sarg'], 96 | emoji: '⚰', 97 | }, 98 | { 99 | name: ['kristallkugel', 'hellseherkugel'], 100 | emoji: '🔮', 101 | }, 102 | { 103 | name: ['messer'], 104 | emoji: '🗡', 105 | }, 106 | // Coming with Unicode/Emoji 13.0 this year, e.g. with Android 11 107 | // { 108 | // name: ['verkleidetes gesicht', 'verkleidet'], 109 | // emoji: '🥸', 110 | // }, 111 | { 112 | name: ['verlassenes haus', 'geisterhaus', 'geistervilla'], 113 | emoji: '🏚', 114 | }, 115 | { 116 | name: ['ohr'], 117 | emoji: '👂', 118 | }, 119 | { 120 | name: ['auge'], 121 | emoji: '👁️', 122 | }, 123 | { 124 | name: ['augen'], 125 | emoji: '👀', 126 | }, 127 | { 128 | name: ['untersuchen'], 129 | emoji: '🕵', 130 | }, 131 | { 132 | name: ['elf'], 133 | emoji: '🧝', 134 | }, 135 | { 136 | name: ['schrei', 'schreie', 'schreien'], 137 | emoji: '😱', 138 | }, 139 | { 140 | name: ['mumie'], 141 | emoji: '🤕', 142 | }, 143 | { 144 | name: ['fee'], 145 | emoji: '🧚', 146 | }, 147 | { 148 | name: ['angst', 'ängstlich'], 149 | emoji: '😨', 150 | }, 151 | { 152 | name: ['feuer'], 153 | emoji: '🔥', 154 | }, 155 | { 156 | name: ['ufo', 'fliegende untertasse'], 157 | emoji: '🛸', 158 | }, 159 | { 160 | name: ['nebel', 'nebelig', 'neblig'], 161 | emoji: '🌫️', 162 | }, 163 | { 164 | name: ['fuß'], 165 | emoji: '🦶', 166 | }, 167 | { 168 | name: ['fußspuren'], 169 | emoji: '👣', 170 | }, 171 | { 172 | name: ['vollmond'], 173 | emoji: '🌕', 174 | }, 175 | { 176 | name: ['urne'], 177 | emoji: '⚱', 178 | }, 179 | { 180 | name: ['genie'], 181 | emoji: '🧞', 182 | }, 183 | { 184 | name: ['goblin'], 185 | emoji: '👺', 186 | }, 187 | { 188 | name: ['geist'], 189 | emoji: '👻', 190 | }, 191 | { 192 | name: ['grünes herz'], 193 | emoji: '💚', 194 | }, 195 | // Coming with Unicode/Emoji 13.0 this year, e.g. with Android 11 196 | // { 197 | // name: ['grabstein', 'grab'], 198 | // emoji: '🪦', 199 | // }, 200 | { 201 | name: ['hochspannung', 'spannend'], 202 | emoji: '⚡', 203 | }, 204 | { 205 | name: ['halloween', 'kürbis', 'hellowien'], 206 | emoji: '🎃', 207 | }, 208 | { 209 | name: ['bein'], 210 | emoji: '🦵', 211 | }, 212 | { 213 | name: ['lollipop', 'lutscher'], 214 | emoji: '🍭', 215 | }, 216 | { 217 | name: ['zauberhaft', 'hexer', 'magier', 'zauberer', 'zaubrer'], 218 | emoji: '🧙', 219 | }, 220 | { 221 | name: ['meerjungfrau'], 222 | emoji: '🧜‍♀️', 223 | }, 224 | { 225 | name: ['meermann'], 226 | emoji: '🧜‍♂️', 227 | }, 228 | { 229 | name: ['meermensch'], 230 | emoji: '🧜', 231 | }, 232 | { 233 | name: ['neumond', 'neumondgesicht'], 234 | emoji: '🌚', 235 | }, 236 | { 237 | name: ['sternennacht', 'nacht', 'sternenklare nacht'], 238 | emoji: '🌃', 239 | }, 240 | { 241 | name: ['ogre', 'oger'], 242 | emoji: '👹', 243 | }, 244 | { 245 | name: ['oranges herz', 'orangenes herz'], 246 | emoji: '🧡', 247 | }, 248 | { 249 | name: ['eule'], 250 | emoji: '🦉', 251 | }, 252 | { 253 | name: ['verkleidung', 'verkleidungen', 'verkleiden', 'verkleide' ], 254 | emoji: '🎭', 255 | }, 256 | { 257 | name: ['schwebende person im anzug', 'schweben', 'schwebe', 'schwebt'], 258 | emoji: '🕴', 259 | }, 260 | { 261 | name: ['prinzessin'], 262 | emoji: '👸', 263 | }, 264 | { 265 | name: ['roboter', 'maschinenmann', 'bot'], 266 | emoji: '🤖', 267 | }, 268 | { 269 | name: ['schädel', 'totenschädel', 'totenkopf'], 270 | emoji: '💀', 271 | }, 272 | { 273 | name: ['totenkopf mit knochen', 'totenkopfflagge', 'pirat'], 274 | emoji: '☠', 275 | }, 276 | { 277 | name: ['lächelnder teufel', 'teufel', 'teuflisch'], 278 | emoji: '😈', 279 | }, 280 | { 281 | name: ['spinne'], 282 | emoji: '🕷', 283 | }, 284 | { 285 | name: ['netz', 'spinnennetz'], 286 | emoji: '🕸', 287 | }, 288 | { 289 | name: ['zunge'], 290 | emoji: '👅', 291 | }, 292 | { 293 | name: ['einhorn'], 294 | emoji: '🦄', 295 | }, 296 | { 297 | name: ['vampir'], 298 | emoji: '🧛', 299 | }, 300 | { 301 | name: ['blume', 'blüte', 'verwelkt'], 302 | emoji: '🥀', 303 | }, 304 | { 305 | name: ['elfin'], 306 | emoji: '🧝‍♀️', 307 | }, 308 | { 309 | name: ['weibliche genie'], 310 | emoji: '🧞‍♀️', 311 | }, 312 | { 313 | name: ['hexe', 'magierin', 'zauberin', 'zaubrerin'], 314 | emoji: '🧙‍♀️', 315 | }, 316 | { 317 | name: ['vampirin'], 318 | emoji: '🧛‍♀️', 319 | }, 320 | { 321 | name: ['weiblicher zombie'], 322 | emoji: '🧟‍♀️', 323 | }, 324 | { 325 | name: ['zombie', 'untote'], 326 | emoji: '🧟', 327 | } 328 | ], 329 | } 330 | -------------------------------------------------------------------------------- /app/lang/el.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'el', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'spooky', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: 'Καραμέλα', 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: 'Φάντασμα', 15 | emoji: '👻', 16 | }, 17 | { 18 | name: 'Απόκριες', 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: 'Βρυκόλακας', 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: 'Μάγισσα', 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: 'Ζόμπι', 31 | emoji: '🧟', 32 | }, 33 | { 34 | name: 'Ιστός', 35 | emoji: '🕸', 36 | }, 37 | ], 38 | } 39 | -------------------------------------------------------------------------------- /app/lang/en.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'en', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: ['spooky'], 7 | uniqueName: '_custom_spooky', 8 | emoji: '761602615326146590', 9 | }, 10 | { 11 | name: ['alien'], 12 | uniqueName: 'Alien', 13 | emoji: '👽', 14 | }, 15 | { 16 | name: ['alienmonster'], 17 | uniqueName: 'Alien Monster', 18 | emoji: '👾', 19 | }, 20 | { 21 | name: ['angry devil'], 22 | uniqueName: 'Angry Face with Horns', 23 | emoji: '👿', 24 | }, 25 | { 26 | name: ['anxious'], 27 | uniqueName: 'Anxious Face with Sweat', 28 | emoji: '😰', 29 | }, 30 | { 31 | name: ['bat'], 32 | uniqueName: 'Bat', 33 | emoji: '🦇', 34 | }, 35 | { 36 | name: ['bone'], 37 | uniqueName: 'Bone', 38 | emoji: '🦴', 39 | }, 40 | { 41 | name: ['brain'], 42 | uniqueName: 'Brain', 43 | emoji: '🧠', 44 | }, 45 | { 46 | name: ['broom'], 47 | uniqueName: 'Broom', 48 | emoji: '🧹', 49 | }, 50 | { 51 | name: ['candle'], 52 | uniqueName: 'Candle', 53 | emoji: '🕯', 54 | }, 55 | { 56 | name: ['candy'], 57 | uniqueName: 'Candy', 58 | emoji: '🍬', 59 | }, 60 | { 61 | name: ['chains'], 62 | uniqueName: 'Chains', 63 | emoji: '⛓', 64 | }, 65 | { 66 | name: ['clown'], 67 | uniqueName: 'Clown Face', 68 | emoji: '🤡', 69 | }, 70 | { 71 | name: ['coffin'], 72 | uniqueName: 'Coffin', 73 | emoji: '⚰', 74 | }, 75 | { 76 | name: ['crystal ball'], 77 | uniqueName: 'Crystal Ball', 78 | emoji: '🔮', 79 | }, 80 | { 81 | name: ['dagger'], 82 | uniqueName: 'Dagger', 83 | emoji: '🗡', 84 | }, 85 | { 86 | name: ['abandoned house'], 87 | uniqueName: 'Derelict House', 88 | emoji: '🏚', 89 | }, 90 | { 91 | name: ['scream'], 92 | uniqueName: 'Face Screaming in Fear', 93 | emoji: '😱', 94 | }, 95 | { 96 | name: ['fear'], 97 | uniqueName: 'Fearful Face', 98 | emoji: '😨', 99 | }, 100 | { 101 | name: ['fire'], 102 | uniqueName: 'Fire', 103 | emoji: '🔥', 104 | }, 105 | { 106 | name: ['full moon'], 107 | uniqueName: 'Full Moon', 108 | emoji: '🌕', 109 | }, 110 | { 111 | name: ['funeral urn'], 112 | uniqueName: 'Funeral Urn', 113 | emoji: '⚱', 114 | }, 115 | { 116 | name: ['ghost'], 117 | uniqueName: 'Ghost', 118 | emoji: '👻', 119 | }, 120 | { 121 | name: ['halloween', 'pumpkin', 'all hallows eve', 'Jack-O-Lantern'], 122 | uniqueName: 'Jack-O-Lantern', 123 | emoji: '🎃', 124 | }, 125 | { 126 | name: ['lollipop'], 127 | uniqueName: 'Lollipop', 128 | emoji: '🍭', 129 | }, 130 | { 131 | name: ['owl'], 132 | uniqueName: 'Owl', 133 | emoji: '🦉', 134 | }, 135 | { 136 | name: ['skull'], 137 | uniqueName: 'Skull', 138 | emoji: '💀', 139 | }, 140 | { 141 | name: ['crossbones'], 142 | uniqueName: 'Skull and Crossbones', 143 | emoji: '☠', 144 | }, 145 | { 146 | name: ['devil'], 147 | uniqueName: 'Smiling Face with Horns', 148 | emoji: '😈', 149 | }, 150 | { 151 | name: ['spider'], 152 | uniqueName: 'Spider', 153 | emoji: '🕷', 154 | }, 155 | { 156 | name: ['web'], 157 | uniqueName: 'Spider Web', 158 | emoji: '🕸', 159 | }, 160 | { 161 | name: ['wilted flower'], 162 | uniqueName: 'Wilted Flower', 163 | emoji: '🥀', 164 | }, 165 | { 166 | name: ['witcher'], 167 | uniqueName: 'Mage', 168 | emoji: '🧙', 169 | }, 170 | { 171 | name: ['witch'], 172 | uniqueName: 'Woman Mage', 173 | emoji: '🧙‍♀️', 174 | }, 175 | { 176 | name: ['vampire'], 177 | uniqueName: 'Vampire', 178 | emoji: '🧛', 179 | }, 180 | { 181 | name: ['female vampire'], 182 | uniqueName: 'Woman Vampire', 183 | emoji: '🧛‍♀️', 184 | }, 185 | { 186 | name: ['zombie'], 187 | uniqueName: 'Zombie', 188 | emoji: '🧟', 189 | }, 190 | { 191 | name: ['female zombie'], 192 | uniqueName: 'Woman Zombie', 193 | emoji: '🧟‍♀️', 194 | }, 195 | ], 196 | mentions: [ 197 | { 198 | name: 'spooky', 199 | emoji: '👻', 200 | }, 201 | ], 202 | } 203 | -------------------------------------------------------------------------------- /app/lang/es.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'es', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'spooky', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: ['dulce', 'caramelo', 'golosina'], 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: ['fantasma', 'espíritu'], 15 | emoji: '👻', 16 | }, 17 | { 18 | name: ['halloween', 'calabaza'], 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: ['vampiro', 'dracula'], 23 | emoji: '🧛', 24 | }, 25 | { 26 | name: ['mago', 'hechicero', 'brujo'], 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: ['zombie', 'muerto'], 31 | emoji: '🧟', 32 | }, 33 | { 34 | name: ['muerte', 'esqueleto', 'cráneo gris'], 35 | emoji: '💀', 36 | }, 37 | { 38 | name: ['telaraña', 'tela de araña'], 39 | emoji: '🕸', 40 | }, 41 | ], 42 | } 43 | -------------------------------------------------------------------------------- /app/lang/fr.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'fr', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: ['spooky'], 7 | uniqueName: '_custom_spooky', 8 | emoji: '761602615326146590', 9 | }, 10 | { 11 | name: ['alien', 'extraterrestre'], 12 | uniqueName: 'Alien', 13 | emoji: '👽', 14 | }, 15 | { 16 | name: ['monstre'], 17 | uniqueName: 'Alien Monster', 18 | emoji: '👾', 19 | }, 20 | { 21 | name: ['anxieux'], 22 | uniqueName: 'Anxious Face with Sweat', 23 | emoji: '😰', 24 | }, 25 | { 26 | name: ['chauve-souris', 'chauve souris'], 27 | uniqueName: 'Bat', 28 | emoji: '🦇', 29 | }, 30 | { 31 | name: ['os'], 32 | uniqueName: 'Bone', 33 | emoji: '🦴', 34 | }, 35 | { 36 | name: ['cerveau', 'brain'], 37 | uniqueName: 'Brain', 38 | emoji: '🧠', 39 | }, 40 | { 41 | name: ['balais'], 42 | uniqueName: 'Broom', 43 | emoji: '🧹', 44 | }, 45 | { 46 | name: ['cierge', 'bougie'], 47 | uniqueName: 'Candle', 48 | emoji: '🕯', 49 | }, 50 | { 51 | name: ['bonbon', 'friandise'], 52 | uniqueName: 'Candy', 53 | emoji: '🍬', 54 | }, 55 | { 56 | name: ['chaines'], 57 | uniqueName: 'Chains', 58 | emoji: '⛓', 59 | }, 60 | { 61 | name: ['clown'], 62 | uniqueName: 'Clown Face', 63 | emoji: '🤡', 64 | }, 65 | { 66 | name: ['cerceuil'], 67 | uniqueName: 'Coffin', 68 | emoji: '⚰', 69 | }, 70 | { 71 | name: ['boule de crystal'], 72 | uniqueName: 'Crystal Ball', 73 | emoji: '🔮', 74 | }, 75 | { 76 | name: ['dague', 'couteau'], 77 | uniqueName: 'Dagger', 78 | emoji: '🗡', 79 | }, 80 | { 81 | name: ['maison abandonnée'], 82 | uniqueName: 'Derelict House', 83 | emoji: '🏚', 84 | }, 85 | { 86 | name: ['cri'], 87 | uniqueName: 'Face Screaming in Fear', 88 | emoji: '😱', 89 | }, 90 | { 91 | name: ['peur'], 92 | uniqueName: 'Fearful Face', 93 | emoji: '😨', 94 | }, 95 | { 96 | name: ['feu', 'fire'], 97 | uniqueName: 'Fire', 98 | emoji: '🔥', 99 | }, 100 | { 101 | name: ['pleine lune'], 102 | uniqueName: 'Full Moon', 103 | emoji: '🌕', 104 | }, 105 | { 106 | name: ['urne'], 107 | uniqueName: 'Funeral Urn', 108 | emoji: '⚱', 109 | }, 110 | { 111 | name: ['fantôme', 'fantome'], 112 | uniqueName: 'Ghost', 113 | emoji: '👻', 114 | }, 115 | { 116 | name: ['halloween', 'citrouille', 'jack-o-lantern'], 117 | uniqueName: 'Jack-O-Lantern', 118 | emoji: '🎃', 119 | }, 120 | { 121 | name: ['sucette'], 122 | uniqueName: 'Lollipop', 123 | emoji: '🍭', 124 | }, 125 | { 126 | name: ['hibou'], 127 | uniqueName: 'Owl', 128 | emoji: '🦉', 129 | }, 130 | { 131 | name: ['crâne', 'crane'], 132 | uniqueName: 'Skull', 133 | emoji: '💀', 134 | }, 135 | { 136 | name: ['diable', 'satan'], 137 | uniqueName: 'Smiling Face with Horns', 138 | emoji: '😈', 139 | }, 140 | { 141 | name: ['araignée', 'araignee'], 142 | uniqueName: 'Spider', 143 | emoji: '🕷', 144 | }, 145 | { 146 | name: ['toile'], 147 | uniqueName: 'Spider Web', 148 | emoji: '🕸', 149 | }, 150 | { 151 | name: ['fleur fané', 'fleur fané'], 152 | uniqueName: 'Wilted Flower', 153 | emoji: '🥀', 154 | }, 155 | { 156 | name: ['sorcier'], 157 | uniqueName: 'Mage', 158 | emoji: '🧙', 159 | }, 160 | { 161 | name: ['sorcière', 'sorciere'], 162 | uniqueName: 'Woman Mage', 163 | emoji: '🧙‍♀️', 164 | }, 165 | { 166 | name: ['vampire'], 167 | uniqueName: 'Vampire', 168 | emoji: '🧛', 169 | }, 170 | { 171 | name: ['zombie', 'mort vivant'], 172 | uniqueName: 'Zombie', 173 | emoji: '🧟', 174 | }, 175 | ], 176 | mentions: [ 177 | { 178 | name: 'spook', 179 | emoji: '👻', 180 | }, 181 | ], 182 | } 183 | -------------------------------------------------------------------------------- /app/lang/gr.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'el', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'spooky', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: 'Καραμέλα', 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: 'Φάντασμα', 15 | emoji: '👻', 16 | }, 17 | { 18 | name: 'Απόκριες', 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: 'Βρυκόλακας', 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: 'Μάγισσα', 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: 'Ζόμπι', 31 | emoji: '🧟', 32 | }, 33 | { 34 | name: 'Ιστός', 35 | emoji: '🕸', 36 | }, 37 | ], 38 | } 39 | -------------------------------------------------------------------------------- /app/lang/hi.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'hi', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'spooky', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: 'toffee', 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: 'bhoot', 15 | emoji: '👻', 16 | }, 17 | { 18 | name: 'darr', 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: 'makdi', 23 | emoji: '🕷', 24 | }, 25 | { 26 | name: 'aatma', 27 | emoji: '💀', 28 | }, 29 | { 30 | name: 'saanp', 31 | emoji: '🐍', 32 | }, 33 | ], 34 | } 35 | -------------------------------------------------------------------------------- /app/lang/nl.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'nl', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'spooky', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: 'snoep', 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: 'spook', 15 | emoji: '👻', 16 | }, 17 | { 18 | name: 'halloween', 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: 'vampier', 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: 'tovenaar', 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: 'zombie', 31 | emoji: '🧟', 32 | }, 33 | { 34 | name: 'ondode', 35 | emoji: '🧟', 36 | }, 37 | ], 38 | } 39 | -------------------------------------------------------------------------------- /app/lang/pt.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'pt', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'spooky', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: ['doce', 'doces'], 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: ['fantasma', 'alma'], 15 | emoji: '👻', 16 | }, 17 | { 18 | name: ['halloween', 'abóbora', 'dia das bruxas'], 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: ['vampiro', 'drácula'], 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: ['bruxo', 'mago', 'feiticeiro'], 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: 'zumbi', 31 | emoji: '🧟', 32 | }, 33 | { 34 | name: ['teia', 'teia de aranha'], 35 | emoji: '🕸', 36 | }, 37 | ], 38 | } 39 | -------------------------------------------------------------------------------- /app/lang/sv.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'sv', 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'spooky', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: ['godis'], 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: 'spöke', 15 | emoji: '👻', 16 | }, 17 | { 18 | name: ['halloween', 'pumpa', 'allhelgonadagen', 'alla helgons dag'], 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: 'vampyr', 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: 'trollkarl', 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: 'zombie', 31 | emoji: '🧟', 32 | }, 33 | { 34 | name: 'spindelnät', 35 | emoji: '🕸', 36 | }, 37 | ], 38 | } 39 | -------------------------------------------------------------------------------- /app/lang/tr.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'tr', //Turkish 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: 'ürpertici', 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: ['karamela', 'Şeker'], 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: ['hayalet', 'ruh'], 15 | emoji: '👻', 16 | }, 17 | { 18 | name: 'cadılar bayramı', 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: 'vampir', 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: ['sihirbaz', 'büyücü', 'dahi'], 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: ['zombi', 'yaşayan ölü', 'yılan tanrı'], 31 | emoji: '🧟', 32 | }, 33 | ], 34 | } -------------------------------------------------------------------------------- /app/lang/zh.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | lang: 'zh', // Mandrin Chinese 3 | words: [ 4 | { 5 | // Please do not delete this one 🙏 6 | name: ['幽灵般的', '害怕的'], 7 | emoji: '761602615326146590', 8 | }, 9 | { 10 | name: ['糖', '糖果'], 11 | emoji: '🍬', 12 | }, 13 | { 14 | name: ['鬼', '幻影'], 15 | emoji: '👻', 16 | }, 17 | { 18 | name: '万圣节', 19 | emoji: '🎃', 20 | }, 21 | { 22 | name: '吸血鬼', 23 | emoji: '🧛🏻‍♂️', 24 | }, 25 | { 26 | name: ['巫师', '觋'], 27 | emoji: '🧙', 28 | }, 29 | { 30 | name: '僵尸', 31 | emoji: '🧟', 32 | }, 33 | ], 34 | } -------------------------------------------------------------------------------- /app/models/servers.js: -------------------------------------------------------------------------------- 1 | const low = require('lowdb') 2 | const FileSync = require('lowdb/adapters/FileSync') 3 | const { resolve } = require('path') 4 | 5 | const adapter = new FileSync(resolve(__dirname, `../db/servers.json`)) 6 | const db = low(adapter) 7 | 8 | // Set some defaults (required if your JSON file is empty) 9 | db.defaults({ servers: [] }).write() 10 | 11 | // Create a guild 12 | exports.createGuild = (guildId) => { 13 | db.get('servers').push({ id: guildId, lang: 'en' }).write() 14 | } 15 | 16 | // Get a guild 17 | exports.getGuild = (guildId) => { 18 | return db.get('servers').find({ id: guildId }).value() 19 | } 20 | 21 | // Change server language 22 | exports.changeLang = (guildId, lang) => { 23 | db.get('servers').find({ id: guildId }).assign({ lang: lang }).write() 24 | } 25 | 26 | // Delete a guild 27 | exports.deleteGuild = (guildId) => { 28 | db.get('servers').remove({ id: guildId }).write() 29 | } 30 | -------------------------------------------------------------------------------- /app/models/trickortreats.js: -------------------------------------------------------------------------------- 1 | const low = require('lowdb') 2 | const FileSync = require('lowdb/adapters/FileSync') 3 | const { resolve } = require('path') 4 | const adapter = new FileSync(resolve(__dirname, `../db/trickortreats.json`)) 5 | const db = low(adapter) 6 | 7 | // Set some defaults (required if your JSON file is empty) 8 | db.defaults({ trickortreats: [] }).write() 9 | 10 | // Find a trick or treat 11 | exports.getTrickOrTreat = (userId) => { 12 | console.log(userId) 13 | return db.get('trickortreats').find({ userId: userId }).value() 14 | } 15 | 16 | // Create a trick or treat 17 | exports.createTrickOrTreat = (userId) => { 18 | db.get('trickortreats').push({ userId: userId, tricks: 0, treats: 0 }).write() 19 | } 20 | 21 | // Trick a user 22 | exports.trick = (userId) => { 23 | const trickOrTreat = db.get('trickortreats').find({ userId: userId }) 24 | 25 | trickOrTreat.assign({ tricks: trickOrTreat.value().tricks + 1, lastPlayed: new Date() }).write() 26 | 27 | return this.getTrickOrTreat(userId) 28 | } 29 | 30 | // Treat a user 31 | exports.treat = (userId) => { 32 | const trickOrTreat = db.get('trickortreats').find({ userId: userId }) 33 | 34 | trickOrTreat.assign({ treats: trickOrTreat.value().treats + 1, lastPlayed: new Date() }).write() 35 | 36 | return this.getTrickOrTreat(userId) 37 | } 38 | -------------------------------------------------------------------------------- /app/sounds/batR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/batR.wav -------------------------------------------------------------------------------- /app/sounds/boo_laughR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/boo_laughR.wav -------------------------------------------------------------------------------- /app/sounds/chainsawR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/chainsawR.wav -------------------------------------------------------------------------------- /app/sounds/creaky_doorR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/creaky_doorR.wav -------------------------------------------------------------------------------- /app/sounds/entrance_mixR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/entrance_mixR.wav -------------------------------------------------------------------------------- /app/sounds/ghostR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/ghostR.wav -------------------------------------------------------------------------------- /app/sounds/howlin_wolfR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/howlin_wolfR.wav -------------------------------------------------------------------------------- /app/sounds/lab2XrcR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/lab2XrcR.wav -------------------------------------------------------------------------------- /app/sounds/mnstrX.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/mnstrX.wav -------------------------------------------------------------------------------- /app/sounds/noreturnR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/noreturnR.wav -------------------------------------------------------------------------------- /app/sounds/ogreR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/ogreR.wav -------------------------------------------------------------------------------- /app/sounds/spooky_skeleton.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/spooky_skeleton.mp3 -------------------------------------------------------------------------------- /app/sounds/thunderR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/thunderR.wav -------------------------------------------------------------------------------- /app/sounds/way_scaryR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/way_scaryR.wav -------------------------------------------------------------------------------- /app/sounds/welcomeR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/welcomeR.wav -------------------------------------------------------------------------------- /app/sounds/windR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/windR.wav -------------------------------------------------------------------------------- /app/sounds/wrong_doorR.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/start-again/spookyBot/4600921afcdbea0ad462cf5cb0a77d2144a03310/app/sounds/wrong_doorR.wav -------------------------------------------------------------------------------- /app/utils/languageCode.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | { name: '(Afan) Oromo', code: 'om' }, 3 | { name: 'Abkhazian', code: 'ab' }, 4 | { name: 'Afar', code: 'aa' }, 5 | { name: 'Afrikaans', code: 'af' }, 6 | { name: 'Albanian', code: 'sq' }, 7 | { name: 'Amharic', code: 'am' }, 8 | { name: 'Arabic', code: 'ar' }, 9 | { name: 'Armenian', code: 'hy' }, 10 | { name: 'Assamese', code: 'as' }, 11 | { name: 'Aymara', code: 'ay' }, 12 | { name: 'Azerbaijani', code: 'az' }, 13 | { name: 'Bashkir', code: 'ba' }, 14 | { name: 'Basque', code: 'eu' }, 15 | { name: 'Bengali', code: 'bn' }, 16 | { name: 'Bhutani', code: 'dz' }, 17 | { name: 'Bihari', code: 'bh' }, 18 | { name: 'Bislama', code: 'bi' }, 19 | { name: 'Breton', code: 'br' }, 20 | { name: 'Bulgarian', code: 'bg' }, 21 | { name: 'Burmese', code: 'my' }, 22 | { name: 'Byelorussian', code: 'be' }, 23 | { name: 'Cambodian', code: 'km' }, 24 | { name: 'Catalan', code: 'ca' }, 25 | { name: 'Chinese', code: 'zh' }, 26 | { name: 'Corsican', code: 'co' }, 27 | { name: 'Croatian', code: 'hr' }, 28 | { name: 'Czech', code: 'cs' }, 29 | { name: 'Danish', code: 'da' }, 30 | { name: 'Dutch', code: 'nl' }, 31 | { name: 'English', code: 'en' }, 32 | { name: 'Esperanto', code: 'eo' }, 33 | { name: 'Estonian', code: 'et' }, 34 | { name: 'Faeroese', code: 'fo' }, 35 | { name: 'Fiji', code: 'fj' }, 36 | { name: 'Finnish', code: 'fi' }, 37 | { name: 'French', code: 'fr' }, 38 | { name: 'Frisian', code: 'fy' }, 39 | { name: 'Galician', code: 'gl' }, 40 | { name: 'Georgian', code: 'ka' }, 41 | { name: 'German', code: 'de' }, 42 | { name: 'Greek', code: 'el' }, 43 | { name: 'Greenlandic', code: 'kl' }, 44 | { name: 'Guarani', code: 'gn' }, 45 | { name: 'Gujarati', code: 'gu' }, 46 | { name: 'Hausa', code: 'ha' }, 47 | { name: 'Hebrew (former iw)', code: 'he' }, 48 | { name: 'Hindi', code: 'hi' }, 49 | { name: 'Hungarian', code: 'hu' }, 50 | { name: 'Icelandic', code: 'is' }, 51 | { name: 'Indonesian (former in)', code: 'id' }, 52 | { name: 'Interlingua', code: 'ia' }, 53 | { name: 'Interlingue', code: 'ie' }, 54 | { name: 'Inupiak', code: 'ik' }, 55 | { name: 'Inuktitut (Eskimo)', code: 'iu' }, 56 | { name: 'Irish', code: 'ga' }, 57 | { name: 'Italian', code: 'it' }, 58 | { name: 'Japanese', code: 'ja' }, 59 | { name: 'Javanese', code: 'jw' }, 60 | { name: 'Kannada', code: 'kn' }, 61 | { name: 'Kashmiri', code: 'ks' }, 62 | { name: 'Kazakh', code: 'kk' }, 63 | { name: 'Kinyarwanda', code: 'rw' }, 64 | { name: 'Kirghiz', code: 'ky' }, 65 | { name: 'Kirundi', code: 'rn' }, 66 | { name: 'Korean', code: 'ko' }, 67 | { name: 'Kurdish', code: 'ku' }, 68 | { name: 'Laothian', code: 'lo' }, 69 | { name: 'Latin', code: 'la' }, 70 | { name: 'Latvian Lettish', code: 'lv' }, 71 | { name: 'Lingala', code: 'ln' }, 72 | { name: 'Lithuanian', code: 'lt' }, 73 | { name: 'Macedonian', code: 'mk' }, 74 | { name: 'Malagasy', code: 'mg' }, 75 | { name: 'Malay', code: 'ms' }, 76 | { name: 'Malayalam', code: 'ml' }, 77 | { name: 'Maltese', code: 'mt' }, 78 | { name: 'Maori', code: 'mi' }, 79 | { name: 'Marathi', code: 'mr' }, 80 | { name: 'Moldavian', code: 'mo' }, 81 | { name: 'Mongolian', code: 'mn' }, 82 | { name: 'Nauru', code: 'na' }, 83 | { name: 'Nepali', code: 'ne' }, 84 | { name: 'Norwegian', code: 'no' }, 85 | { name: 'Occitan', code: 'oc' }, 86 | { name: 'Oriya', code: 'or' }, 87 | { name: 'Pashto Pushto', code: 'ps' }, 88 | { name: 'Persian', code: 'fa' }, 89 | { name: 'Polish', code: 'pl' }, 90 | { name: 'Portuguese', code: 'pt' }, 91 | { name: 'Punjabi', code: 'pa' }, 92 | { name: 'Quechua', code: 'qu' }, 93 | { name: 'Rhaeto Romance', code: 'rm' }, 94 | { name: 'Romanian', code: 'ro' }, 95 | { name: 'Russian', code: 'ru' }, 96 | { name: 'Samoan', code: 'sm' }, 97 | { name: 'Sangro', code: 'sg' }, 98 | { name: 'Sanskrit', code: 'sa' }, 99 | { name: 'Scots Gaelic', code: 'gd' }, 100 | { name: 'Serbian', code: 'sr' }, 101 | { name: 'Serbo Croatian', code: 'sh' }, 102 | { name: 'Sesotho', code: 'st' }, 103 | { name: 'Setswana', code: 'tn' }, 104 | { name: 'Shona', code: 'sn' }, 105 | { name: 'Sindhi', code: 'sd' }, 106 | { name: 'Singhalese', code: 'si' }, 107 | { name: 'Siswati', code: 'ss' }, 108 | { name: 'Slovak', code: 'sk' }, 109 | { name: 'Slovenian', code: 'sl' }, 110 | { name: 'Somali', code: 'so' }, 111 | { name: 'Spanish', code: 'es' }, 112 | { name: 'Sudanese', code: 'su' }, 113 | { name: 'Swahili', code: 'sw' }, 114 | { name: 'Swedish', code: 'sv' }, 115 | { name: 'Tagalog', code: 'tl' }, 116 | { name: 'Tajik', code: 'tg' }, 117 | { name: 'Tamil', code: 'ta' }, 118 | { name: 'Tatar', code: 'tt' }, 119 | { name: 'Tegulu', code: 'te' }, 120 | { name: 'Thai', code: 'th' }, 121 | { name: 'Tibetan', code: 'bo' }, 122 | { name: 'Tigrinya', code: 'ti' }, 123 | { name: 'Tonga', code: 'to' }, 124 | { name: 'Tsonga', code: 'ts' }, 125 | { name: 'Turkish', code: 'tr' }, 126 | { name: 'Turkmen', code: 'tk' }, 127 | { name: 'Twi', code: 'tw' }, 128 | { name: 'Uigur', code: 'ug' }, 129 | { name: 'Ukrainian', code: 'uk' }, 130 | { name: 'Urdu', code: 'ur' }, 131 | { name: 'Uzbek', code: 'uz' }, 132 | { name: 'Vietnamese', code: 'vi' }, 133 | { name: 'Volapuk', code: 'vo' }, 134 | { name: 'Welch', code: 'cy' }, 135 | { name: 'Wolof', code: 'wo' }, 136 | { name: 'Xhosa', code: 'xh' }, 137 | { name: 'Yiddish (former ji)', code: 'yi' }, 138 | { name: 'Yoruba', code: 'yo' }, 139 | { name: 'Zhuang', code: 'za' }, 140 | { name: 'Zulu', code: 'zu' }, 141 | ] 142 | -------------------------------------------------------------------------------- /app/utils/reactMessage.js: -------------------------------------------------------------------------------- 1 | const { MessageEmbed } = require('discord.js') 2 | const { colors } = require('../config/config.json') 3 | const { getGuild, createGuild } = require('../models/servers') 4 | 5 | String.prototype.contains = function (toCheck) { 6 | return this.indexOf(toCheck) >= 0 7 | } 8 | 9 | const translationNameContainsWord = (translationName, fullMessage) => { 10 | if (translationName instanceof Array) { 11 | return translationName 12 | .map((n) => { 13 | let regex = new RegExp('\\b' + n + '\\b', 'g') 14 | return regex.test(fullMessage) 15 | }) 16 | .reduce((a, b) => a || b) 17 | } else { 18 | return fullMessage.contains(translationName) 19 | } 20 | } 21 | 22 | const translationNameContainsUser = (translationName, mentions) => { 23 | // Search all mentions for trigger words, cast translationName to an array if not for compactness 24 | return mentions.members.some((m) => 25 | (typeof translationName === 'string' ? [translationName] : translationName).some((w) => 26 | m.displayName.toLowerCase().contains(w) 27 | ) 28 | ) 29 | } 30 | 31 | module.exports = async (guildId, message, webhook) => { 32 | let guildData = await getGuild(guildId) 33 | if (guildData === undefined) { 34 | await createGuild(guildId) 35 | guildData = await getGuild(guildId) 36 | } 37 | 38 | const translation = await require(`../lang/${guildData.lang}.js`) 39 | const fullMessage = message.content.toLowerCase() 40 | 41 | let triggeredEmoji = [] 42 | let triggeredWord = [] 43 | 44 | translation.words.forEach((w) => { 45 | if (translationNameContainsWord(w.name, fullMessage)) { 46 | message.react(w.emoji) 47 | triggeredEmoji.push(w.emoji) 48 | triggeredWord.push(w.name) 49 | } 50 | }) 51 | translation.mentions.forEach((m) => { 52 | if (translationNameContainsUser(m.name, message.mentions)) { 53 | message.react(m.emoji) 54 | triggeredEmoji.push(m.emoji) 55 | triggeredWord.push(w.name) 56 | } 57 | }) 58 | 59 | if (triggeredEmoji.length != 0) { 60 | const privateEmbed = new MessageEmbed() 61 | .setColor(colors.primary) 62 | .setTitle(`Reaction trigger`) 63 | .setDescription(`**Message:**\n${message.content}\n\n**Reacted with:**\n${triggeredEmoji.join(' ')}`) 64 | .setFooter(`${message.author.tag} | #${message.channel.name} | ${message.guild.name}`, message.guild.iconURL()) 65 | 66 | webhook.send(privateEmbed) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /docker-compose.dev.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | 3 | services: 4 | spooky-bot: 5 | image: spookybot/spookybot:latest 6 | build: 7 | context: . 8 | dockerfile: docker/spooky-node/DockerfileProd 9 | args: 10 | - NODE_VERSION=12.18.2 11 | volumes: 12 | - ./app:/spooky/app/:rw 13 | - ./package.json:/spooky/package.json 14 | -------------------------------------------------------------------------------- /docker/spooky-node/DockerfileDev: -------------------------------------------------------------------------------- 1 | ARG NODE_VERSION 2 | 3 | FROM node:${NODE_VERSION} AS build 4 | 5 | COPY . /spooky 6 | 7 | WORKDIR /spooky 8 | RUN npm cache clean --force 9 | RUN rm -rf node_modules 10 | RUN npm install 11 | 12 | FROM node:${NODE_VERSION} 13 | WORKDIR /spooky 14 | COPY --from=build /spooky /spooky 15 | 16 | ENTRYPOINT ["npm", "run", "dev"] 17 | -------------------------------------------------------------------------------- /docker/spooky-node/DockerfileProd: -------------------------------------------------------------------------------- 1 | ARG NODE_VERSION 2 | 3 | FROM node:${NODE_VERSION} 4 | 5 | COPY . /spooky 6 | 7 | WORKDIR /spooky 8 | RUN npm cache clean --force 9 | RUN rm -rf node_modules 10 | RUN npm install --production 11 | 12 | RUN rm -rf app/config 13 | RUN rm -rf app/db 14 | ENTRYPOINT ["npm", "run", "start"] 15 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "NODE_ENV": "dev" 4 | }, 5 | "ignore": ["db/*"] 6 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spookybot", 3 | "version": "1.2.0", 4 | "description": "A spooky Discord bot", 5 | "main": "app/core.js", 6 | "repository": "git@github.com:LucasCtrl/spookyBot.git", 7 | "author": "LucasCtrl ", 8 | "license": "MIT", 9 | "private": true, 10 | "dependencies": { 11 | "@discordjs/opus": "^0.3.2", 12 | "discord.js": "^12.3.1", 13 | "ffmpeg-static": "^4.2.7", 14 | "lowdb": "^1.0.0" 15 | }, 16 | "devDependencies": { 17 | "eslint": "^7.10.0", 18 | "eslint-config-prettier": "^6.12.0", 19 | "eslint-plugin-prettier": "^3.1.4", 20 | "nodemon": "^2.0.4", 21 | "prettier": "^2.1.2" 22 | }, 23 | "scripts": { 24 | "dev": "nodemon --inspect ./app/core.js", 25 | "start": "node app/core.js" 26 | } 27 | } 28 | --------------------------------------------------------------------------------