├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── greetings.yml │ └── label.yml ├── .gitignore - (python) ├── .idea ├── .gitignore ├── Discord-moderation-bot.iml ├── inspectionProfiles │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Javascript ├── README.md ├── commands │ ├── Economy │ │ ├── economy.js │ │ └── requirements.txt │ ├── Fun │ │ ├── fun.js │ │ └── requirements.txt │ ├── Google search │ │ ├── requirements.txt │ │ └── search.js │ ├── Info │ │ ├── Info.js │ │ └── requirements.txt │ ├── Meme │ │ ├── meme.js │ │ └── requirements.txt │ ├── Moderation │ │ ├── mod.js │ │ └── requirements.txt │ ├── Music │ │ ├── music.js │ │ └── requirements.txt │ ├── Paginator │ │ ├── paginator.js │ │ └── requirements.txt │ ├── Polls │ │ ├── polls.js │ │ └── requirements.txt │ ├── giveaway │ │ ├── giveaway.js │ │ └── requirements.txt │ └── tictactoe │ │ ├── requirements.txt │ │ └── tic.js ├── global-req.txt └── main.js ├── LICENSE ├── Python ├── Cogs │ ├── Economy │ │ ├── economy.py │ │ ├── main.json │ │ └── requirements.txt │ ├── Fun │ │ ├── fun.py │ │ └── requirements.txt │ ├── Google search │ │ ├── googlesearch.py │ │ └── requirements.txt │ ├── Info │ │ ├── Info.py │ │ └── requirements.txt │ ├── Meme │ │ ├── meme.py │ │ └── requrements.txt │ ├── Moderation │ │ ├── mod.py │ │ ├── reports.json │ │ └── requirements.txt │ ├── Music │ │ ├── music.py │ │ └── requirements.txt │ ├── Paginator │ │ ├── Paginator.py │ │ └── requirements.txt │ ├── Polls │ │ ├── poll.py │ │ └── requirements.txt │ ├── giveaway │ │ ├── giveaway.py │ │ ├── requirements.txt │ │ └── util.py │ └── tictactoe │ │ ├── requirements.txt │ │ └── tic_tac_toe.py ├── README.md ├── SECURITY.md ├── global-req.txt └── main.py ├── README.md └── vids └── Video 1.gif /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Intents:** 27 | - eg: all 28 | 29 | **language:** 30 | - ag. python 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | steps: 12 | - uses: actions/first-interaction@v1 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | issue-message: 'Message that will be displayed on users first issue' 16 | pr-message: 'Message that will be displayed on users first pull request' 17 | -------------------------------------------------------------------------------- /.github/workflows/label.yml: -------------------------------------------------------------------------------- 1 | # This workflow will triage pull requests and apply a label based on the 2 | # paths that are modified in the pull request. 3 | # 4 | # To use this workflow, you will need to set up a .github/labeler.yml 5 | # file with configuration. For more information, see: 6 | # https://github.com/actions/labeler 7 | 8 | name: Labeler 9 | on: [pull_request] 10 | 11 | jobs: 12 | label: 13 | 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: read 17 | pull-requests: write 18 | 19 | steps: 20 | - uses: actions/labeler@v2 21 | with: 22 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 23 | -------------------------------------------------------------------------------- /.gitignore - (python): -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/Discord-moderation-bot.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | discord: betches.py#2117. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for taking the time to contribute to the repository 😄 it really helps us improve 4 | 5 | When contributing to this repository, please first discuss the change you wish to make via issue, 6 | email, or any other method with the owners of this repository before making a change. 7 | 8 | Please note we have a code of conduct, please follow it in all your interactions with the project. 9 | 10 | ## Pull Request Process 11 | 12 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 13 | build. 14 | 2. Update the README.md with details of changes to the interface, this includes new environment 15 | variables, exposed ports, useful file locations and container parameters. 16 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 17 | Pull Request would represent. 18 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 19 | do not have permission to do that, you may request the second reviewer to merge it for you. 20 | -------------------------------------------------------------------------------- /Javascript/README.md: -------------------------------------------------------------------------------- 1 | # This section is under development. 2 | -------------------------------------------------------------------------------- /Javascript/commands/Economy/economy.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Economy/economy.js -------------------------------------------------------------------------------- /Javascript/commands/Economy/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Economy/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/Fun/fun.js: -------------------------------------------------------------------------------- 1 | const Discord = require("discord.js") 2 | const mathutils = require("../mathutils") 3 | 4 | function useCommands(msg, prefix) { 5 | if (msg.content.toLowerCase().startsWith(prefix + "eightball")) { // Check if the message starts with the prefix and eightball so users can use the command 6 | const ballresponce = [ 7 | "Yes", "No", "Take a wild guess...", "Very doubtful", 8 | "Sure", "Without a doubt", "Most likely", "Might be possible", 9 | "You'll be the judge", "No... (╯°□°)╯︵ ┻━┻", "No!", 10 | "bruh no","Maybe, 👀","gg","I don't know" 11 | ] // Tells our program what answers we want from the bot 12 | 13 | const answer = ballresponce[mathutils.getRandomInt(0, ballresponce.length - 1)] // Gets a random answer from the responces section 14 | 15 | msg.channel.send(answer) // Sends the answer (when I ask if I am a good person it always says no (Yaumama writing) ) 16 | } 17 | 18 | if (msg.content.toLowerCase().startsWith(prefix + "hotlevel")) { // Check if the message is the prefix and hotlevel 19 | const hot = mathutils.getRandomInt(0, 100) // Get the percentage of hot the person is 20 | let emoji // Make an unsigned variable for us to set later 21 | 22 | if (hot > 75) { // Check if the hot level is above these levels and add emojis accordingly 23 | emoji = "💞" 24 | } else if (hot > 50) { 25 | emoji = "💖" 26 | } else if (hot > 25) { 27 | emoji = "❤" 28 | } else { 29 | emoji = "💔" 30 | } 31 | 32 | msg.channel.send("**" + msg.member.displayName + "** is " + hot + "% hot! " + emoji) // Send the hot level and emoji 33 | } 34 | } 35 | 36 | module.exports = {useCommands} 37 | -------------------------------------------------------------------------------- /Javascript/commands/Fun/requirements.txt: -------------------------------------------------------------------------------- 1 | git + node.js + discord.js 2 | -------------------------------------------------------------------------------- /Javascript/commands/Google search/requirements.txt: -------------------------------------------------------------------------------- 1 | git + node.js + discord.js + googlethis 2 | -------------------------------------------------------------------------------- /Javascript/commands/Google search/search.js: -------------------------------------------------------------------------------- 1 | const Discord = require("discord.js") 2 | const google = require("googlethis") 3 | 4 | async function useCommands(msg, prefix) { 5 | if (msg.content.toLowerCase().startsWith(prefix + "search")) { 6 | if (msg.content.substring(prefix.length + "search".length) === "") { 7 | return msg.channel.send("Please specify a search!\nUsage: ```" + prefix + "search ```") 8 | } // Check if the person that used it didn't specify a query 9 | 10 | let message = undefined 11 | 12 | msg.channel.send("Searching... 🔍").then(m => { 13 | message = m 14 | }) // Send a message and make the message variable m so we can edit it later 15 | 16 | const options = { 17 | page: 0, 18 | safe: true, 19 | additional_params: { 20 | hl: "en" 21 | } 22 | } // Make options for the search 23 | 24 | const responces = await google.search(msg.content.substring(prefix.length + "search".length), options) // Search for the query 25 | const firstresponce = responces.results[0] // Get the first responce of the search 26 | 27 | const embed = new Discord.MessageEmbed() 28 | .setTitle("Search results") 29 | .setDescription("Query: " + msg.content.substring(prefix.length + "search".length)) 30 | .addField("Search result:", firstresponce.title + "\nUrl: " + firstresponce.url) // Make the embed with the first responce's url and title 31 | 32 | message.edit({embeds: [embed], content: "Found!"}) // Edit the message so people see the query 33 | } 34 | } 35 | 36 | module.exports = {useCommands} // Export our command 37 | -------------------------------------------------------------------------------- /Javascript/commands/Info/Info.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Info/Info.js -------------------------------------------------------------------------------- /Javascript/commands/Info/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Info/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/Meme/meme.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Meme/meme.js -------------------------------------------------------------------------------- /Javascript/commands/Meme/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Meme/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/Moderation/mod.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Moderation/mod.js -------------------------------------------------------------------------------- /Javascript/commands/Moderation/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Moderation/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/Music/music.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Music/music.js -------------------------------------------------------------------------------- /Javascript/commands/Music/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Music/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/Paginator/paginator.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Paginator/paginator.js -------------------------------------------------------------------------------- /Javascript/commands/Paginator/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Paginator/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/Polls/polls.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Polls/polls.js -------------------------------------------------------------------------------- /Javascript/commands/Polls/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/Polls/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/giveaway/giveaway.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/giveaway/giveaway.js -------------------------------------------------------------------------------- /Javascript/commands/giveaway/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/giveaway/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/tictactoe/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/tictactoe/requirements.txt -------------------------------------------------------------------------------- /Javascript/commands/tictactoe/tic.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/commands/tictactoe/tic.js -------------------------------------------------------------------------------- /Javascript/global-req.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/Javascript/global-req.txt -------------------------------------------------------------------------------- /Javascript/main.js: -------------------------------------------------------------------------------- 1 | const Discord = require("discord.js") // Require the library this is built in 2 | const client = new Discord.Client({intents: new Discord.Intents(32767)}) // Make a new discord client with all intents 3 | const TOKEN = process.env.token // Let the program know what bot we want to login with 4 | const prefix = "~" // Tell the program what prefix we want to use 5 | 6 | const fun = require("./commands/Fun/fun") // Require our fun commands. 7 | const search = require("./commands/Google search/search") // Require our search commands 8 | 9 | client.on("ready", () => { 10 | console.log("Ready!") // Say that we are ready so we know when to use our bot 11 | }) 12 | 13 | client.on("messageCreate", async msg => { 14 | fun.useCommands(msg, prefix) 15 | search.useCommands(msg, prefix) 16 | }) 17 | 18 | client.login(TOKEN) // Login to our bot with our token 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Pogrammar 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 | -------------------------------------------------------------------------------- /Python/Cogs/Economy/economy.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | import asyncio 4 | import os 5 | import json 6 | import random 7 | 8 | 9 | os.chdir("D:\Discord bots\Okinomia") 10 | 11 | 12 | client = commands.Bot(command_prefix='ok ') 13 | 14 | client.remove_command("help") 15 | 16 | 17 | @client.event 18 | async def on_ready(): 19 | print('Bot is ready') 20 | 21 | 22 | #################################################################### 23 | #################################################################### 24 | # Main code starts :) 25 | 26 | mainshop = [{"name":"Watch","price":100,"description":"Time"}, 27 | {"name":"Laptop","price":1000,"description":"Work"}, 28 | {"name":"PC","price":10000,"description":"Gaming"}, 29 | {"name":"Ferrari","price":99999,"description":"Sports Car"}] 30 | 31 | @client.command(aliases=['bal']) 32 | async def balance(ctx): 33 | await open_account(ctx.author) 34 | user = ctx.author 35 | 36 | users = await get_bank_data() 37 | 38 | wallet_amt = users[str(user.id)]["wallet"] 39 | bank_amt = users[str(user.id)]["bank"] 40 | 41 | em = discord.Embed(title=f'{ctx.author.name} Balance',color = discord.Color.red()) 42 | em.add_field(name="Wallet Balance", value=wallet_amt) 43 | em.add_field(name='Bank Balance',value=bank_amt) 44 | await ctx.send(embed= em) 45 | 46 | @client.command() 47 | async def beg(ctx): 48 | await open_account(ctx.author) 49 | user = ctx.author 50 | 51 | users = await get_bank_data() 52 | 53 | earnings = random.randrange(101) 54 | 55 | await ctx.send(f'{ctx.author.mention} Got {earnings} coins!!') 56 | 57 | users[str(user.id)]["wallet"] += earnings 58 | 59 | with open("mainbank.json",'w') as f: 60 | json.dump(users,f) 61 | 62 | 63 | @client.command(aliases=['with']) 64 | async def withdraw(ctx,amount = None): 65 | await open_account(ctx.author) 66 | if amount == None: 67 | await ctx.send("Please enter the amount") 68 | return 69 | 70 | bal = await update_bank(ctx.author) 71 | 72 | amount = int(amount) 73 | 74 | if amount > bal[1]: 75 | await ctx.send('You do not have sufficient balance') 76 | return 77 | if amount < 0: 78 | await ctx.send('Amount must be positive!') 79 | return 80 | 81 | await update_bank(ctx.author,amount) 82 | await update_bank(ctx.author,-1*amount,'bank') 83 | await ctx.send(f'{ctx.author.mention} You withdrew {amount} coins') 84 | 85 | 86 | @client.command(aliases=['dep']) 87 | async def deposit(ctx,amount = None): 88 | await open_account(ctx.author) 89 | if amount == None: 90 | await ctx.send("Please enter the amount") 91 | return 92 | 93 | bal = await update_bank(ctx.author) 94 | 95 | amount = int(amount) 96 | 97 | if amount > bal[0]: 98 | await ctx.send('You do not have sufficient balance') 99 | return 100 | if amount < 0: 101 | await ctx.send('Amount must be positive!') 102 | return 103 | 104 | await update_bank(ctx.author,-1*amount) 105 | await update_bank(ctx.author,amount,'bank') 106 | await ctx.send(f'{ctx.author.mention} You deposited {amount} coins') 107 | 108 | 109 | @client.command(aliases=['sn']) 110 | async def send(ctx,member : discord.Member,amount = None): 111 | await open_account(ctx.author) 112 | await open_account(member) 113 | if amount == None: 114 | await ctx.send("Please enter the amount") 115 | return 116 | 117 | bal = await update_bank(ctx.author) 118 | if amount == 'all': 119 | amount = bal[0] 120 | 121 | amount = int(amount) 122 | 123 | if amount > bal[0]: 124 | await ctx.send('You do not have sufficient balance') 125 | return 126 | if amount < 0: 127 | await ctx.send('Amount must be positive!') 128 | return 129 | 130 | await update_bank(ctx.author,-1*amount,'bank') 131 | await update_bank(member,amount,'bank') 132 | await ctx.send(f'{ctx.author.mention} You gave {member} {amount} coins') 133 | 134 | 135 | @client.command(aliases=['ro']) 136 | async def rob(ctx,member : discord.Member): 137 | await open_account(ctx.author) 138 | await open_account(member) 139 | bal = await update_bank(member) 140 | 141 | 142 | if bal[0]<100: 143 | await ctx.send('It is useless to rob him :(') 144 | return 145 | 146 | earning = random.randrange(0,bal[0]) 147 | 148 | await update_bank(ctx.author,earning) 149 | await update_bank(member,-1*earning) 150 | await ctx.send(f'{ctx.author.mention} You robbed {member} and got {earning} coins') 151 | 152 | 153 | @client.command() 154 | async def slots(ctx,amount = None): 155 | await open_account(ctx.author) 156 | if amount == None: 157 | await ctx.send("Please enter the amount") 158 | return 159 | 160 | bal = await update_bank(ctx.author) 161 | 162 | amount = int(amount) 163 | 164 | if amount > bal[0]: 165 | await ctx.send('You do not have sufficient balance') 166 | return 167 | if amount < 0: 168 | await ctx.send('Amount must be positive!') 169 | return 170 | final = [] 171 | for i in range(3): 172 | a = random.choice(['X','O','Q']) 173 | 174 | final.append(a) 175 | 176 | await ctx.send(str(final)) 177 | 178 | if final[0] == final[1] or final[1] == final[2] or final[0] == final[2]: 179 | await update_bank(ctx.author,2*amount) 180 | await ctx.send(f'You won :) {ctx.author.mention}') 181 | else: 182 | await update_bank(ctx.author,-1*amount) 183 | await ctx.send(f'You lose :( {ctx.author.mention}') 184 | 185 | 186 | @client.command() 187 | async def shop(ctx): 188 | em = discord.Embed(title = "Shop") 189 | 190 | for item in mainshop: 191 | name = item["name"] 192 | price = item["price"] 193 | desc = item["description"] 194 | em.add_field(name = name, value = f"${price} | {desc}") 195 | 196 | await ctx.send(embed = em) 197 | 198 | 199 | 200 | @client.command() 201 | async def buy(ctx,item,amount = 1): 202 | await open_account(ctx.author) 203 | 204 | res = await buy_this(ctx.author,item,amount) 205 | 206 | if not res[0]: 207 | if res[1]==1: 208 | await ctx.send("That Object isn't there!") 209 | return 210 | if res[1]==2: 211 | await ctx.send(f"You don't have enough money in your wallet to buy {amount} {item}") 212 | return 213 | 214 | 215 | await ctx.send(f"You just bought {amount} {item}") 216 | 217 | 218 | @client.command() 219 | async def bag(ctx): 220 | await open_account(ctx.author) 221 | user = ctx.author 222 | users = await get_bank_data() 223 | 224 | try: 225 | bag = users[str(user.id)]["bag"] 226 | except: 227 | bag = [] 228 | 229 | 230 | em = discord.Embed(title = "Bag") 231 | for item in bag: 232 | name = item["item"] 233 | amount = item["amount"] 234 | 235 | em.add_field(name = name, value = amount) 236 | 237 | await ctx.send(embed = em) 238 | 239 | 240 | async def buy_this(user,item_name,amount): 241 | item_name = item_name.lower() 242 | name_ = None 243 | for item in mainshop: 244 | name = item["name"].lower() 245 | if name == item_name: 246 | name_ = name 247 | price = item["price"] 248 | break 249 | 250 | if name_ == None: 251 | return [False,1] 252 | 253 | cost = price*amount 254 | 255 | users = await get_bank_data() 256 | 257 | bal = await update_bank(user) 258 | 259 | if bal[0] 75: 33 | emoji = "💞" 34 | elif hot > 50: 35 | emoji = "💖" 36 | elif hot > 25: 37 | emoji = "❤" 38 | else: 39 | emoji = "💔" 40 | 41 | await ctx.respond(f"**{user.name}** is **{hot:.2f}%** hot {emoji}") 42 | 43 | def setup(bot): 44 | bot.add_cog(Fun(bot)) 45 | -------------------------------------------------------------------------------- /Python/Cogs/Fun/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord -------------------------------------------------------------------------------- /Python/Cogs/Google search/googlesearch.py: -------------------------------------------------------------------------------- 1 | import google 2 | from googlesearch import search 3 | import discord 4 | from discord.ext import commands 5 | from discord.commands import Option #Importing the packages 6 | import datetime 7 | from discord.commands import slash_command 8 | 9 | class Search(commands.Cog): 10 | def __init__(self, bot): 11 | self.bot = bot 12 | 13 | @slash_command(guild_ids=[...]) 14 | async def search(self, ctx, query: Option(str)): 15 | msg = await ctx.respond(f"Searching...🔍") 16 | embed = discord.Embed(title=f"Search results", description=f"Query: {query}") 17 | for j in search(query, num=5, stop=5, pause=2):#increase num and stop for the amount of results you want 18 | embed.add_field(name="Search result:", value=j) 19 | await msg.edit(embed=embed) 20 | 21 | 22 | 23 | def setup(bot): 24 | bot.add_cog(Search(bot)) 25 | 26 | -------------------------------------------------------------------------------- /Python/Cogs/Google search/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord 2 | googlesearch 3 | beautifulsoup4 as bs4 4 | -------------------------------------------------------------------------------- /Python/Cogs/Info/Info.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from discord.commands import Option #Importing the packages 4 | import datetime 5 | from discord.commands import slash_command 6 | 7 | 8 | class Info(commands.Cog): 9 | def __init__(self, bot):#to Initialise 10 | self.bot = bot 11 | 12 | @slash_command() 13 | async def userinfo(self, ctx, user: Option(discord.Member)): # b'\xfc' 14 | date_format = "%a, %d %b %Y %I:%M %p" 15 | 16 | embed = discord.Embed(color=0xdfa3ff, description=user.mention) 17 | embed.set_author(name=str(user), icon_url=user.avatar_url) 18 | embed.set_thumbnail(url=user.avatar_url) 19 | embed.add_field(name="Joined", value=user.joined_at.strftime(date_format)) 20 | 21 | embed.add_field(name="Registered", value=user.created_at.strftime(date_format)) 22 | if len(user.roles) > 1: 23 | role_string = ' '.join([r.mention for r in user.roles][1:]) 24 | embed.add_field(name="Roles [{}]".format(len(user.roles)-1), value=role_string, inline=False) 25 | 26 | 27 | perm_string = ', '.join([str(p[0]).replace("_", " ").title() for p in user.guild_permissions if p[1]]) 28 | 29 | embed.add_field(name="Guild permissions", value=perm_string, inline=False) 30 | embed.set_footer(text='ID: ' + str(user.id)) 31 | return await ctx.respond(embed=embed) 32 | 33 | def setup(bot): 34 | bot.add_cog(Info(bot)) 35 | -------------------------------------------------------------------------------- /Python/Cogs/Info/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord -------------------------------------------------------------------------------- /Python/Cogs/Meme/meme.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord import Embed 3 | from discord.ext import commands 4 | import asyncpraw 5 | import random 6 | 7 | 8 | class Meme(commands.Cog): 9 | def __init__(self, bot):#to Initialise 10 | self.bot = bot 11 | 12 | @commands.command() 13 | async def meme(self, ctx, subred="memes"): # default subreddit is memes, later in the command you can select one of your choice (example: !meme python --> chooses r/python reddit post) 14 | msg = await ctx.send('Loading ... ') 15 | 16 | reddit = asyncpraw.Reddit(client_id='clientid', 17 | client_secret='clientsecret', 18 | username='username', 19 | password='password', 20 | user_agent='useragent') 21 | 22 | subreddit = await reddit.subreddit(subred) 23 | all_subs = [] 24 | top = subreddit.top(limit=250) # bot will choose between the top 250 memes 25 | 26 | async for submission in top: 27 | all_subs.append(submission) 28 | 29 | random_sub = random.choice(all_subs) 30 | 31 | name = random_sub.title 32 | url = random_sub.url 33 | 34 | embed = Embed(title=f'__{name}__', colour=discord.Colour.random(), timestamp=ctx.message.created_at, url=url) 35 | 36 | embed.set_image(url=url) 37 | embed.set_author(name=ctx.message.author, icon_url=ctx.author.avatar_url) 38 | embed.set_footer(text='Here is your meme!') 39 | await ctx.send(embed=embed) 40 | await msg.edit(content=f' :white_check_mark:') # < and > remove the embed link 41 | return 42 | 43 | def setup(bot): 44 | bot.add_cog(Meme(bot)) 45 | -------------------------------------------------------------------------------- /Python/Cogs/Meme/requrements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord 2 | asyncpraw 3 | -------------------------------------------------------------------------------- /Python/Cogs/Moderation/mod.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from discord.commands import slash_command 4 | from discord.commands import Option #Importing the packages 5 | import datetime 6 | import json 7 | 8 | 9 | class Moderation(commands.Cog): 10 | def __init__(self, bot):#to Initialise 11 | self.bot = bot 12 | 13 | 14 | @slash_command(guild_ids=[...]) 15 | @commands.has_permissions(manage_messages = True) 16 | async def clear(self, ctx, amount: Option(int)): 17 | await ctx.channel.purge(limit = amount)#Get the channel where the command is executed, then purge no. of messages provided 18 | await ctx.respond("Done.")#respond because in slash commands the response shows a little reply thing on top, for that you need ctx.respond 19 | 20 | 21 | @slash_command(guild_ids=[...]) 22 | @commands.has_permissions(kick_members = True) 23 | async def kick(self, ctx, member: Option(discord.Member)): 24 | 25 | await member.kick(reason=None)#kick th member with no reason. you can add another option with "str" as the first param 26 | await ctx.respond("Done.") 27 | 28 | 29 | @slash_command(guild_ids=[...]) 30 | @commands.has_permissions(ban_members = True) 31 | async def ban(self, ctx, member: Option(discord.Member)): 32 | 33 | await member.ban(reason=None, delete_message_days=0)#ban and dont delete any messages 34 | await ctx.respond("Done.") 35 | 36 | 37 | @commands.command()#Because unban doesnt work with slash commands 38 | @commands.has_permissions(ban_members = True) 39 | async def unban(self, ctx, member : discord.Member): 40 | 41 | await member.unban(member, reason=None) 42 | await ctx.respond("Done.") 43 | 44 | @slash_command(guild_ids=[...]) 45 | @commands.has_permissions(manage_roles = True) 46 | async def mute(self, ctx, member: Option(discord.Member)): 47 | muted_role = ctx.guild.get_role(1234567890)#get the muted role with ID 48 | 49 | await member.add_roles(muted_role)#add the mute role 50 | 51 | await ctx.respond("The member has been muted") 52 | 53 | 54 | @slash_command(guild_ids=[...]) 55 | @commands.has_permissions(manage_roles = True) 56 | async def unmute(self, ctx, member: Option(discord.Member)): 57 | muted_role = ctx.guild.get_role(1234567890) 58 | 59 | await member.remove_roles(muted_role)#remove muted role 60 | 61 | await ctx.respond("The member has been unmuted") 62 | 63 | 64 | @slash_command(guild_ids=[...]) 65 | async def membercount(self, ctx): 66 | await ctx.respond(ctx.guild.member_count)#get guild no. of members 67 | 68 | @slash_command(guild_ids=[...]) 69 | async def timeout(self, ctx, member: Option(discord.Member), minutes: Option(int)): 70 | """Apply a timeout to a member""" 71 | 72 | duration = datetime.timedelta(minutes=minutes) 73 | await member.timeout_for(duration)#timeout for the amount of time given, then remove timeout 74 | await ctx.reply(f"Member timed out for {minutes} minutes.") 75 | 76 | 77 | #Warn command section(it is still in the same class)----------------------------------------------------- 78 | 79 | @slash_command(guild_ids=[...]) 80 | async def warnings(self, ctx, member: Option(discord.Member)): 81 | await self.open_account(member) 82 | 83 | users = await self.get_user_data() 84 | 85 | warns = users[str(member.id)]["warns"] 86 | 87 | await ctx.respond(f"{member.name} has {warns} warns.") 88 | 89 | @slash_command(guild_ids=[...]) 90 | @commands.has_permissions(kick_members = True) 91 | async def warn(self, ctx, member: Option(discord.Member)): 92 | await self.open_account(member) 93 | 94 | users = await self.get_user_data() 95 | 96 | warns = await self.warn(member) 97 | 98 | await ctx.respond(f"<@{member.id}> has been warned. They now have {warns} warns.") 99 | 100 | 101 | async def open_account(self, user): 102 | with open ("./Cogs/Moderation/reports.json","r")as f: 103 | users = json.load(f) 104 | if str (user.id) in users: 105 | return False 106 | else: 107 | users[str(user.id)] = {} 108 | users[str(user.id)]["warns"] = 0 109 | 110 | with open("./Cogs/Moderation/reports.json","w")as f: 111 | json.dump(users, f) 112 | 113 | 114 | async def get_user_data(self): 115 | with open ("./Cogs/Moderation/reports.json","r")as f: 116 | users = json.load(f) 117 | return users 118 | 119 | 120 | async def warn(self, user, change = 1, mode = "warns"): 121 | users = await self.get_user_data() 122 | 123 | users[str(user.id)][mode] += change 124 | 125 | with open("./Cogs/Moderation/reports.json","w")as f: 126 | json.dump(users, f) 127 | 128 | warns = users[str(user.id)][mode] 129 | 130 | return warns 131 | 132 | def setup(bot): 133 | bot.add_cog(Moderation(bot)) 134 | -------------------------------------------------------------------------------- /Python/Cogs/Moderation/reports.json: -------------------------------------------------------------------------------- 1 | { 2 | {"12334567890123456789": {"warns": 2}, "12334567890123456789": {"warns": 1} 3 | } 4 | -------------------------------------------------------------------------------- /Python/Cogs/Moderation/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord -------------------------------------------------------------------------------- /Python/Cogs/Music/music.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import functools 3 | import itertools 4 | import math 5 | import random 6 | 7 | import discord 8 | import youtube_dl 9 | from async_timeout import timeout 10 | from discord.ext import commands 11 | 12 | # Silence useless bug reports messages 13 | youtube_dl.utils.bug_reports_message = lambda: '' 14 | 15 | class VoiceError(Exception): 16 | pass 17 | 18 | 19 | class YTDLError(Exception): 20 | pass 21 | 22 | 23 | class YTDLSource(discord.PCMVolumeTransformer): 24 | YTDL_OPTIONS = { 25 | 'format': 'bestaudio/best', 26 | 'extractaudio': True, 27 | 'audioformat': 'mp3', 28 | 'outtmpl': '%(extractor)s-%(id)s-%(title)s.%(ext)s', 29 | 'restrictfilenames': True, 30 | 'noplaylist': True, 31 | 'nocheckcertificate': True, 32 | 'ignoreerrors': False, 33 | 'logtostderr': False, 34 | 'quiet': True, 35 | 'no_warnings': True, 36 | 'default_search': 'auto', 37 | 'source_address': '0.0.0.0', 38 | } 39 | 40 | FFMPEG_OPTIONS = { 41 | 'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 42 | 'options': '-vn', 43 | } 44 | 45 | ytdl = youtube_dl.YoutubeDL(YTDL_OPTIONS) 46 | 47 | def __init__(self, ctx: commands.Context, source: discord.FFmpegPCMAudio, *, data: dict, volume: float = 0.5): 48 | super().__init__(source, volume) 49 | 50 | self.requester = ctx.author 51 | self.channel = ctx.channel 52 | self.data = data 53 | 54 | self.uploader = data.get('uploader') 55 | self.uploader_url = data.get('uploader_url') 56 | date = data.get('upload_date') 57 | self.upload_date = date[6:8] + '.' + date[4:6] + '.' + date[0:4] 58 | self.title = data.get('title') 59 | self.thumbnail = data.get('thumbnail') 60 | self.description = data.get('description') 61 | self.duration = self.parse_duration(int(data.get('duration'))) 62 | self.tags = data.get('tags') 63 | self.url = data.get('webpage_url') 64 | self.views = data.get('view_count') 65 | self.likes = data.get('like_count') 66 | self.dislikes = data.get('dislike_count') 67 | self.stream_url = data.get('url') 68 | 69 | def __str__(self): 70 | return '**{0.title}** by **{0.uploader}**'.format(self) 71 | 72 | @classmethod 73 | async def create_source(cls, ctx: commands.Context, search: str, *, loop: asyncio.BaseEventLoop = None): 74 | loop = loop or asyncio.get_event_loop() 75 | 76 | partial = functools.partial(cls.ytdl.extract_info, search, download=False, process=False) 77 | data = await loop.run_in_executor(None, partial) 78 | 79 | if data is None: 80 | raise YTDLError('Couldn\'t find anything that matches `{}`'.format(search)) 81 | 82 | if 'entries' not in data: 83 | process_info = data 84 | else: 85 | process_info = None 86 | for entry in data['entries']: 87 | if entry: 88 | process_info = entry 89 | break 90 | 91 | if process_info is None: 92 | raise YTDLError('Couldn\'t find anything that matches `{}`'.format(search)) 93 | 94 | webpage_url = process_info['webpage_url'] 95 | partial = functools.partial(cls.ytdl.extract_info, webpage_url, download=False) 96 | processed_info = await loop.run_in_executor(None, partial) 97 | 98 | if processed_info is None: 99 | raise YTDLError('Couldn\'t fetch `{}`'.format(webpage_url)) 100 | 101 | if 'entries' not in processed_info: 102 | info = processed_info 103 | else: 104 | info = None 105 | while info is None: 106 | try: 107 | info = processed_info['entries'].pop(0) 108 | except IndexError: 109 | raise YTDLError('Couldn\'t retrieve any matches for `{}`'.format(webpage_url)) 110 | 111 | return cls(ctx, discord.FFmpegPCMAudio(info['url'], **cls.FFMPEG_OPTIONS), data=info) 112 | 113 | @staticmethod 114 | def parse_duration(duration: int): 115 | minutes, seconds = divmod(duration, 60) 116 | hours, minutes = divmod(minutes, 60) 117 | days, hours = divmod(hours, 24) 118 | 119 | duration = [] 120 | if days > 0: 121 | duration.append('{} days'.format(days)) 122 | if hours > 0: 123 | duration.append('{} hours'.format(hours)) 124 | if minutes > 0: 125 | duration.append('{} minutes'.format(minutes)) 126 | if seconds > 0: 127 | duration.append('{} seconds'.format(seconds)) 128 | 129 | return ', '.join(duration) 130 | 131 | 132 | class Song: 133 | __slots__ = ('source', 'requester') 134 | 135 | def __init__(self, source: YTDLSource): 136 | self.source = source 137 | self.requester = source.requester 138 | 139 | def create_embed(self): 140 | embed = (discord.Embed(title='Now playing', 141 | description='```css\n{0.source.title}\n```'.format(self), 142 | color=discord.Color.random()) 143 | .add_field(name='Duration', value=self.source.duration) 144 | .add_field(name='Requested by', value=self.requester.mention) 145 | .add_field(name='Uploader', value='[{0.source.uploader}]({0.source.uploader_url})'.format(self)) 146 | .add_field(name='URL', value='[Click]({0.source.url})'.format(self)) 147 | .set_thumbnail(url=self.source.thumbnail)) 148 | 149 | return embed 150 | 151 | 152 | class SongQueue(asyncio.Queue): 153 | def __getitem__(self, item): 154 | if isinstance(item, slice): 155 | return list(itertools.islice(self._queue, item.start, item.stop, item.step)) 156 | else: 157 | return self._queue[item] 158 | 159 | def __iter__(self): 160 | return self._queue.__iter__() 161 | 162 | def __len__(self): 163 | return self.qsize() 164 | 165 | def clear(self): 166 | self._queue.clear() 167 | 168 | def shuffle(self): 169 | random.shuffle(self._queue) 170 | 171 | def remove(self, index: int): 172 | del self._queue[index] 173 | 174 | 175 | class VoiceState: 176 | def __init__(self, bot: commands.Bot, ctx: commands.Context): 177 | self.bot = bot 178 | self._ctx = ctx 179 | 180 | self.current = None 181 | self.voice = None 182 | self.next = asyncio.Event() 183 | self.songs = SongQueue() 184 | 185 | self._loop = False 186 | self._volume = 0.5 187 | self.skip_votes = set() 188 | 189 | self.audio_player = bot.loop.create_task(self.audio_player_task()) 190 | 191 | def __del__(self): 192 | self.audio_player.cancel() 193 | 194 | @property 195 | def loop(self): 196 | return self._loop 197 | 198 | @loop.setter 199 | def loop(self, value: bool): 200 | self._loop = value 201 | 202 | @property 203 | def volume(self): 204 | return self._volume 205 | 206 | @volume.setter 207 | def volume(self, value: float): 208 | self._volume = value 209 | 210 | @property 211 | def is_playing(self): 212 | return self.voice and self.current 213 | 214 | async def audio_player_task(self): 215 | while True: 216 | self.next.clear() 217 | 218 | if not self.loop: 219 | # Try to get the next song within 3 minutes. 220 | # If no song will be added to the queue in time, 221 | # the player will disconnect due to performance 222 | # reasons. 223 | try: 224 | async with timeout(180): # 3 minutes 225 | self.current = await self.songs.get() 226 | except asyncio.TimeoutError: 227 | self.bot.loop.create_task(self.stop()) 228 | return 229 | 230 | self.current.source.volume = self._volume 231 | self.voice.play(self.current.source, after=self.play_next_song) 232 | await self.current.source.channel.send(embed=self.current.create_embed()) 233 | 234 | await self.next.wait() 235 | 236 | def play_next_song(self, error=None): 237 | if error: 238 | raise VoiceError(str(error)) 239 | 240 | self.next.set() 241 | 242 | def skip(self): 243 | self.skip_votes.clear() 244 | 245 | if self.is_playing: 246 | self.voice.stop() 247 | 248 | async def stop(self): 249 | self.songs.clear() 250 | 251 | if self.voice: 252 | await self.voice.disconnect() 253 | self.voice = None 254 | 255 | 256 | class Music(commands.Cog): 257 | def __init__(self, bot: commands.Bot): 258 | self.bot = bot 259 | self.voice_states = {} 260 | 261 | def get_voice_state(self, ctx: commands.Context): 262 | state = self.voice_states.get(ctx.guild.id) 263 | if not state: 264 | state = VoiceState(self.bot, ctx) 265 | self.voice_states[ctx.guild.id] = state 266 | 267 | return state 268 | 269 | def cog_unload(self): 270 | for state in self.voice_states.values(): 271 | self.bot.loop.create_task(state.stop()) 272 | 273 | def cog_check(self, ctx: commands.Context): 274 | if not ctx.guild: 275 | raise commands.NoPrivateMessage('This command can\'t be used in DM channels.') 276 | 277 | return True 278 | 279 | async def cog_before_invoke(self, ctx: commands.Context): 280 | ctx.voice_state = self.get_voice_state(ctx) 281 | 282 | async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): 283 | await ctx.send('An error occurred: {}'.format(str(error))) 284 | 285 | @commands.command(name='join', invoke_without_subcommand=True) 286 | async def _join(self, ctx: commands.Context): 287 | """Joins a voice channel.""" 288 | 289 | destination = ctx.author.voice.channel 290 | if ctx.voice_state.voice: 291 | await ctx.voice_state.voice.move_to(destination) 292 | return 293 | 294 | ctx.voice_state.voice = await destination.connect() 295 | 296 | @commands.command(name='summon') 297 | @commands.has_permissions(manage_guild=True) 298 | async def _summon(self, ctx: commands.Context, *, channel: discord.VoiceChannel = None): 299 | """Summons the bot to a voice channel. 300 | If no channel was specified, it joins your channel. 301 | """ 302 | 303 | if not channel and not ctx.author.voice: 304 | raise VoiceError('You are neither connected to a voice channel nor specified a channel to join.') 305 | 306 | destination = channel or ctx.author.voice.channel 307 | if ctx.voice_state.voice: 308 | await ctx.voice_state.voice.move_to(destination) 309 | return 310 | 311 | ctx.voice_state.voice = await destination.connect() 312 | 313 | @commands.command(name='leave', aliases=['disconnect']) 314 | @commands.has_permissions(manage_guild=True) 315 | async def _leave(self, ctx: commands.Context): 316 | """Clears the queue and leaves the voice channel.""" 317 | 318 | if not ctx.voice_state.voice: 319 | return await ctx.send('Not connected to any voice channel.') 320 | 321 | await ctx.voice_state.stop() 322 | del self.voice_states[ctx.guild.id] 323 | 324 | @commands.command(name='volume') 325 | async def _volume(self, ctx: commands.Context, *, volume: int): 326 | """Sets the volume of the player.""" 327 | 328 | if not ctx.voice_state.is_playing: 329 | return await ctx.send('Nothing being played at the moment.') 330 | 331 | if 0 > volume > 100: 332 | return await ctx.send('Volume must be between 0 and 100') 333 | 334 | ctx.voice_state.volume = volume / 100 335 | await ctx.send('Volume of the player set to {}%'.format(volume)) 336 | 337 | @commands.command(name='now', aliases=['current', 'playing']) 338 | async def _now(self, ctx: commands.Context): 339 | """Displays the currently playing song.""" 340 | 341 | await ctx.send(embed=ctx.voice_state.current.create_embed()) 342 | 343 | @commands.command(name='pause') 344 | async def _pause(self, ctx: commands.Context): 345 | """Pauses the currently playing song.""" 346 | 347 | if not ctx.voice_state.is_playing and ctx.voice_state.voice.is_playing(): 348 | ctx.voice_state.voice.pause() 349 | await ctx.message.add_reaction('⏯') 350 | 351 | @commands.command(name='resume') 352 | async def _resume(self, ctx: commands.Context): 353 | """Resumes a currently paused song.""" 354 | 355 | if not ctx.voice_state.is_playing and ctx.voice_state.voice.is_paused(): 356 | ctx.voice_state.voice.resume() 357 | await ctx.message.add_reaction('⏯') 358 | 359 | @commands.command(name='stop') 360 | async def _stop(self, ctx: commands.Context): 361 | """Stops playing song and clears the queue.""" 362 | 363 | ctx.voice_state.songs.clear() 364 | 365 | if not ctx.voice_state.is_playing: 366 | ctx.voice_state.voice.stop() 367 | await ctx.message.add_reaction('⏹') 368 | 369 | @commands.command(name='skip') 370 | async def _skip(self, ctx: commands.Context): 371 | """Vote to skip a song. The requester can automatically skip. 372 | 3 skip votes are needed for the song to be skipped. 373 | """ 374 | 375 | if not ctx.voice_state.is_playing: 376 | return await ctx.send('Not playing any music right now...') 377 | 378 | voter = ctx.message.author 379 | if voter == ctx.voice_state.current.requester: 380 | await ctx.message.add_reaction('⏭') 381 | ctx.voice_state.skip() 382 | 383 | elif voter.id not in ctx.voice_state.skip_votes: 384 | ctx.voice_state.skip_votes.add(voter.id) 385 | total_votes = len(ctx.voice_state.skip_votes) 386 | 387 | if total_votes >= 3: 388 | await ctx.message.add_reaction('⏭') 389 | ctx.voice_state.skip() 390 | else: 391 | await ctx.send('Skip vote added, currently at **{}/3**'.format(total_votes)) 392 | 393 | else: 394 | await ctx.send('You have already voted to skip this song.') 395 | 396 | @commands.command(name='queue') 397 | async def _queue(self, ctx: commands.Context, *, page: int = 1): 398 | """Shows the player's queue. 399 | You can optionally specify the page to show. Each page contains 10 elements. 400 | """ 401 | 402 | if len(ctx.voice_state.songs) == 0: 403 | return await ctx.send('Empty queue.') 404 | 405 | items_per_page = 10 406 | pages = math.ceil(len(ctx.voice_state.songs) / items_per_page) 407 | 408 | start = (page - 1) * items_per_page 409 | end = start + items_per_page 410 | 411 | queue = '' 412 | for i, song in enumerate(ctx.voice_state.songs[start:end], start=start): 413 | queue += '`{0}.` [**{1.source.title}**]({1.source.url})\n'.format(i + 1, song) 414 | 415 | embed = (discord.Embed(description='**{} tracks:**\n\n{}'.format(len(ctx.voice_state.songs), queue)) 416 | .set_footer(text='Viewing page {}/{}'.format(page, pages))) 417 | await ctx.send(embed=embed) 418 | 419 | @commands.command(name='shuffle') 420 | async def _shuffle(self, ctx: commands.Context): 421 | """Shuffles the queue.""" 422 | 423 | if len(ctx.voice_state.songs) == 0: 424 | return await ctx.send('Empty queue.') 425 | 426 | ctx.voice_state.songs.shuffle() 427 | await ctx.message.add_reaction('✅') 428 | 429 | @commands.command(name='remove') 430 | async def _remove(self, ctx: commands.Context, index: int): 431 | """Removes a song from the queue at a given index.""" 432 | 433 | if len(ctx.voice_state.songs) == 0: 434 | return await ctx.send('Empty queue.') 435 | 436 | ctx.voice_state.songs.remove(index - 1) 437 | await ctx.message.add_reaction('✅') 438 | 439 | @commands.command(name='loop') 440 | async def _loop(self, ctx: commands.Context): 441 | """Loops the currently playing song. 442 | Invoke this command again to unloop the song. 443 | """ 444 | 445 | if not ctx.voice_state.is_playing: 446 | return await ctx.send('Nothing being played at the moment.') 447 | 448 | # Inverse boolean value to loop and unloop. 449 | ctx.voice_state.loop = not ctx.voice_state.loop 450 | await ctx.message.add_reaction('✅') 451 | 452 | @commands.command(name='play') 453 | async def _play(self, ctx: commands.Context, *, search: str): 454 | """Plays a song. 455 | If there are songs in the queue, this will be queued until the 456 | other songs finished playing. 457 | This command automatically searches from various sites if no URL is provided. 458 | A list of these sites can be found here: https://rg3.github.io/youtube-dl/supportedsites.html 459 | """ 460 | 461 | if not ctx.voice_state.voice: 462 | await ctx.invoke(self._join) 463 | 464 | 465 | 466 | 467 | await ctx.send("Searching...🔍") 468 | try: 469 | source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop) 470 | except YTDLError as e: 471 | await ctx.send('An error occurred while processing this request: {}'.format(str(e))) 472 | else: 473 | 474 | song = Song(source) 475 | 476 | 477 | await ctx.voice_state.songs.put(song) 478 | await ctx.send('Enqueued {}'.format(str(source))) 479 | 480 | @_join.before_invoke 481 | @_play.before_invoke 482 | async def ensure_voice_state(self, ctx: commands.Context): 483 | if not ctx.author.voice or not ctx.author.voice.channel: 484 | raise commands.CommandError('You are not connected to any voice channel.') 485 | 486 | if ctx.voice_client: 487 | if ctx.voice_client.channel != ctx.author.voice.channel: 488 | raise commands.CommandError('Bot is already in a voice channel.') 489 | 490 | def setup(bot): 491 | bot.add_cog(Music(bot)) -------------------------------------------------------------------------------- /Python/Cogs/Music/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord 2 | youtube-dl 3 | pynacl 4 | FFmpeg -------------------------------------------------------------------------------- /Python/Cogs/Paginator/Paginator.py: -------------------------------------------------------------------------------- 1 | 2 | # Note that the below examples use a Slash Command Group in a cog for better organization - it's not required for using ext.pages. 3 | import asyncio 4 | 5 | import discord 6 | from discord.commands import SlashCommandGroup 7 | from discord.ext import commands, pages 8 | 9 | 10 | class PageTest(commands.Cog): 11 | def __init__(self, bot): 12 | self.bot = bot 13 | self.pages = [ 14 | "Page 1", 15 | [ 16 | discord.Embed(title="Page 2, Embed 1"), 17 | discord.Embed(title="Page 2, Embed 2"), 18 | ], 19 | "Page Three", 20 | discord.Embed(title="Page Four"), 21 | discord.Embed(title="Page Five"), 22 | [ 23 | discord.Embed(title="Page Six, Embed 1"), 24 | discord.Embed(title="Page Seven, Embed 2"), 25 | ], 26 | ] 27 | self.pages[3].set_image( 28 | url="https://c.tenor.com/pPKOYQpTO8AAAAAM/monkey-developer.gif" 29 | ) 30 | self.pages[4].add_field( 31 | name="Example Field", value="Example Value", inline=False 32 | ) 33 | self.pages[4].add_field( 34 | name="Another Example Field", value="Another Example Value", inline=False 35 | ) 36 | 37 | self.more_pages = [ 38 | "Second Page One", 39 | discord.Embed(title="Second Page Two"), 40 | discord.Embed(title="Second Page Three"), 41 | ] 42 | 43 | self.even_more_pages = ["11111", "22222", "33333"] 44 | 45 | def get_pages(self): 46 | return self.pages 47 | 48 | pagetest = SlashCommandGroup("pagetest", "Commands for testing ext.pages") 49 | 50 | # These examples use a Slash Command Group in a cog for better organization - it's not required for using ext.pages. 51 | @pagetest.command(name="default") 52 | async def pagetest_default(self, ctx: discord.ApplicationContext): 53 | """Demonstrates using the paginator with the default options.""" 54 | paginator = pages.Paginator(pages=self.get_pages()) 55 | await paginator.respond(ctx.interaction, ephemeral=False) 56 | 57 | @pagetest.command(name="hidden") 58 | async def pagetest_hidden(self, ctx: discord.ApplicationContext): 59 | """Demonstrates using the paginator with disabled buttons hidden.""" 60 | paginator = pages.Paginator(pages=self.get_pages(), show_disabled=False) 61 | await paginator.respond(ctx.interaction, ephemeral=False) 62 | 63 | @pagetest.command(name="loop") 64 | async def pagetest_loop(self, ctx: discord.ApplicationContext): 65 | """Demonstrates using the loop_pages option.""" 66 | paginator = pages.Paginator(pages=self.get_pages(), loop_pages=True) 67 | await paginator.respond(ctx.interaction, ephemeral=False) 68 | 69 | @pagetest.command(name="strings") 70 | async def pagetest_strings(self, ctx: discord.ApplicationContext): 71 | """Demonstrates passing a list of strings as pages.""" 72 | paginator = pages.Paginator( 73 | pages=["Page 1", "Page 2", "Page 3"], loop_pages=True 74 | ) 75 | await paginator.respond(ctx.interaction, ephemeral=False) 76 | 77 | @pagetest.command(name="timeout") 78 | async def pagetest_timeout(self, ctx: discord.ApplicationContext): 79 | """Demonstrates having the buttons be disabled when the paginator view times out.""" 80 | paginator = pages.Paginator( 81 | pages=self.get_pages(), disable_on_timeout=True, timeout=30 82 | ) 83 | await paginator.respond(ctx.interaction, ephemeral=False) 84 | 85 | @pagetest.command(name="remove_buttons") 86 | async def pagetest_remove(self, ctx: discord.ApplicationContext): 87 | """Demonstrates using the default buttons, but removing some of them.""" 88 | paginator = pages.Paginator(pages=self.get_pages()) 89 | paginator.remove_button("first") 90 | paginator.remove_button("last") 91 | await paginator.respond(ctx.interaction, ephemeral=False) 92 | 93 | @pagetest.command(name="init") 94 | async def pagetest_init(self, ctx: discord.ApplicationContext): 95 | """Demonstrates how to pass a list of custom buttons when creating the Paginator instance.""" 96 | pagelist = [ 97 | pages.PaginatorButton( 98 | "first", label="<<-", style=discord.ButtonStyle.green 99 | ), 100 | pages.PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), 101 | pages.PaginatorButton( 102 | "page_indicator", style=discord.ButtonStyle.gray, disabled=True 103 | ), 104 | pages.PaginatorButton("next", label="->", style=discord.ButtonStyle.green), 105 | pages.PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), 106 | ] 107 | paginator = pages.Paginator( 108 | pages=self.get_pages(), 109 | show_disabled=True, 110 | show_indicator=True, 111 | use_default_buttons=False, 112 | custom_buttons=pagelist, 113 | loop_pages=True, 114 | ) 115 | await paginator.respond(ctx.interaction, ephemeral=False) 116 | 117 | @pagetest.command(name="custom_buttons") 118 | async def pagetest_custom_buttons(self, ctx: discord.ApplicationContext): 119 | """Demonstrates adding buttons to the paginator when the default buttons are not used.""" 120 | paginator = pages.Paginator( 121 | pages=self.get_pages(), 122 | use_default_buttons=False, 123 | loop_pages=False, 124 | show_disabled=False, 125 | ) 126 | paginator.add_button( 127 | pages.PaginatorButton( 128 | "prev", label="<", style=discord.ButtonStyle.green, loop_label="lst" 129 | ) 130 | ) 131 | paginator.add_button( 132 | pages.PaginatorButton( 133 | "page_indicator", style=discord.ButtonStyle.gray, disabled=True 134 | ) 135 | ) 136 | paginator.add_button( 137 | pages.PaginatorButton( 138 | "next", style=discord.ButtonStyle.green, loop_label="fst" 139 | ) 140 | ) 141 | await paginator.respond(ctx.interaction, ephemeral=False) 142 | 143 | @pagetest.command(name="emoji_buttons") 144 | async def pagetest_emoji_buttons(self, ctx: discord.ApplicationContext): 145 | """Demonstrates using emojis for the paginator buttons instead of labels.""" 146 | page_buttons = [ 147 | pages.PaginatorButton( 148 | "first", emoji="⏪", style=discord.ButtonStyle.green 149 | ), 150 | pages.PaginatorButton("prev", emoji="⬅", style=discord.ButtonStyle.green), 151 | pages.PaginatorButton( 152 | "page_indicator", style=discord.ButtonStyle.gray, disabled=True 153 | ), 154 | pages.PaginatorButton("next", emoji="➡", style=discord.ButtonStyle.green), 155 | pages.PaginatorButton("last", emoji="⏩", style=discord.ButtonStyle.green), 156 | ] 157 | paginator = pages.Paginator( 158 | pages=self.get_pages(), 159 | show_disabled=True, 160 | show_indicator=True, 161 | use_default_buttons=False, 162 | custom_buttons=page_buttons, 163 | loop_pages=True, 164 | ) 165 | await paginator.respond(ctx.interaction, ephemeral=False) 166 | 167 | @pagetest.command(name="custom_view") 168 | async def pagetest_custom_view(self, ctx: discord.ApplicationContext): 169 | """Demonstrates passing a custom view to the paginator.""" 170 | view = discord.ui.View() 171 | view.add_item(discord.ui.Button(label="Test Button, Does Nothing", row=1)) 172 | view.add_item( 173 | discord.ui.Select( 174 | placeholder="Test Select Menu, Does Nothing", 175 | options=[ 176 | discord.SelectOption( 177 | label="Example Option", 178 | value="Example Value", 179 | description="This menu does nothing!", 180 | ) 181 | ], 182 | ) 183 | ) 184 | paginator = pages.Paginator(pages=self.get_pages(), custom_view=view) 185 | await paginator.respond(ctx.interaction, ephemeral=False) 186 | 187 | @pagetest.command(name="groups") 188 | async def pagetest_groups(self, ctx: discord.ApplicationContext): 189 | """Demonstrates using page groups to switch between different sets of pages.""" 190 | page_buttons = [ 191 | pages.PaginatorButton( 192 | "first", label="<<-", style=discord.ButtonStyle.green 193 | ), 194 | pages.PaginatorButton("prev", label="<-", style=discord.ButtonStyle.green), 195 | pages.PaginatorButton( 196 | "page_indicator", style=discord.ButtonStyle.gray, disabled=True 197 | ), 198 | pages.PaginatorButton("next", label="->", style=discord.ButtonStyle.green), 199 | pages.PaginatorButton("last", label="->>", style=discord.ButtonStyle.green), 200 | ] 201 | view = discord.ui.View() 202 | view.add_item(discord.ui.Button(label="Test Button, Does Nothing", row=2)) 203 | view.add_item( 204 | discord.ui.Select( 205 | placeholder="Test Select Menu, Does Nothing", 206 | options=[ 207 | discord.SelectOption( 208 | label="Example Option", 209 | value="Example Value", 210 | description="This menu does nothing!", 211 | ) 212 | ], 213 | ) 214 | ) 215 | page_groups = [ 216 | pages.PageGroup( 217 | pages=self.get_pages(), 218 | label="Main Page Group", 219 | description="Main Pages for Main Things", 220 | ), 221 | pages.PageGroup( 222 | pages=[ 223 | "Second Set of Pages, Page 1", 224 | "Second Set of Pages, Page 2", 225 | "Look, it's group 2, page 3!", 226 | ], 227 | label="Second Page Group", 228 | description="Secondary Pages for Secondary Things", 229 | custom_buttons=page_buttons, 230 | use_default_buttons=False, 231 | custom_view=view, 232 | ), 233 | ] 234 | paginator = pages.Paginator(pages=page_groups, show_menu=True) 235 | await paginator.respond(ctx.interaction, ephemeral=False) 236 | 237 | @pagetest.command(name="update") 238 | async def pagetest_update(self, ctx: discord.ApplicationContext): 239 | """Demonstrates updating an existing paginator instance with different options.""" 240 | paginator = pages.Paginator(pages=self.get_pages(), show_disabled=False) 241 | await paginator.respond(ctx.interaction) 242 | await asyncio.sleep(3) 243 | await paginator.update(show_disabled=True, show_indicator=False) 244 | 245 | @pagetest.command(name="target") 246 | async def pagetest_target(self, ctx: discord.ApplicationContext): 247 | """Demonstrates sending the paginator to a different target than where it was invoked.""" 248 | paginator = pages.Paginator(pages=self.get_pages()) 249 | await paginator.respond(ctx.interaction, target=ctx.interaction.user) 250 | 251 | @commands.command() 252 | async def pagetest_prefix(self, ctx: commands.Context): 253 | """Demonstrates using the paginator with a prefix-based command.""" 254 | paginator = pages.Paginator(pages=self.get_pages(), use_default_buttons=False) 255 | paginator.add_button( 256 | pages.PaginatorButton("prev", label="<", style=discord.ButtonStyle.green) 257 | ) 258 | paginator.add_button( 259 | pages.PaginatorButton( 260 | "page_indicator", style=discord.ButtonStyle.gray, disabled=True 261 | ) 262 | ) 263 | paginator.add_button( 264 | pages.PaginatorButton("next", style=discord.ButtonStyle.green) 265 | ) 266 | await paginator.send(ctx) 267 | 268 | @commands.command() 269 | async def pagetest_target(self, ctx: commands.Context): 270 | """Demonstrates sending the paginator to a different target than where it was invoked (prefix-command version).""" 271 | paginator = pages.Paginator(pages=self.get_pages()) 272 | await paginator.send(ctx, target=ctx.author, target_message="Paginator sent!") 273 | 274 | 275 | def setup(bot): 276 | bot.add_cog(PageTest(bot)) -------------------------------------------------------------------------------- /Python/Cogs/Paginator/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord -------------------------------------------------------------------------------- /Python/Cogs/Polls/poll.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands, ui 3 | from discord.commands import Option 4 | from discord.commands import slash_command 5 | from discord.ui import button 6 | 7 | class Poll(commands.Cog): 8 | def __init__(self, bot): 9 | self.bot = bot 10 | 11 | @slash_command(guild_ids=[...]) 12 | async def poll(ctx, 13 | question: Option(str), 14 | a: Option(str), 15 | b: Option(str)): 16 | embed = discord.Embed(title=question, 17 | description=f"🅰️: {a}\n 🅱️: {b}") 18 | await ctx.respond(embed=embed) 19 | msg = await ctx.interaction.original_message() 20 | await msg.add_reaction('🅰️') 21 | await msg.add_reaction('🅱️') 22 | 23 | def setup(bot): 24 | bot.add_cog(Poll(bot)) 25 | -------------------------------------------------------------------------------- /Python/Cogs/Polls/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord -------------------------------------------------------------------------------- /Python/Cogs/giveaway/giveaway.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | from discord.ext.commands import Cog 4 | from discord.ext.commands import command, has_permissions, has_role 5 | from discord import Member 6 | from discord import Embed,File 7 | from typing import Optional 8 | from random import choice 9 | from asyncio import TimeoutError, sleep 10 | from util import convert 11 | 12 | class Giveaway(commands.Cog): 13 | def __init__(self,bot): 14 | self.bot = bot 15 | self.cancelled = False 16 | 17 | @commands.command(name="gift", aliases=["giveaway", "gcreate", "gcr"]) 18 | @has_permissions(manage_guild=True) 19 | # @has_role("admin") 20 | async def create_giveaway(self, ctx): 21 | #Ask Questions 22 | embed = Embed(title="Giveaway Time!!✨", 23 | description="Time for a new Giveaway. Answer the following questions in 25 seconds each for the Giveaway", 24 | color=ctx.author.color) 25 | await ctx.send(embed=embed) 26 | questions=["In Which channel do you want to host the giveaway?", 27 | "For How long should the Giveaway be hosted ? type number followed (s|m|h|d)", 28 | "What is the Prize?"] 29 | answers = [] 30 | #Check Author 31 | def check(m): 32 | return m.author == ctx.author and m.channel == ctx.channel 33 | 34 | for i, question in enumerate(questions): 35 | embed = Embed(title=f"Question {i}", 36 | description=question) 37 | await ctx.send(embed=embed) 38 | try: 39 | message = await self.bot.wait_for('message', timeout=25, check=check) 40 | except TimeoutError: 41 | await ctx.send("You didn't answer the questions in Time") 42 | return 43 | answers.append(message.content) 44 | #Check if Channel Id is valid 45 | try: 46 | channel_id = int(answers[0][2:-1]) 47 | except: 48 | await ctx.send(f"The Channel provided was wrong. The channel should be {ctx.channel.mention}") 49 | return 50 | 51 | channel = self.bot.get_channel(channel_id) 52 | time = convert(answers[1]) 53 | #Check if Time is valid 54 | if time == -1: 55 | await ctx.send("The Time format was wrong") 56 | return 57 | elif time == -2: 58 | await ctx.send("The Time was not conventional number") 59 | return 60 | prize = answers[2] 61 | 62 | await ctx.send(f"Your giveaway will be hosted in {channel.mention} and will last for {answers[1]}") 63 | embed = Embed(title="Giveaway Time !!", 64 | description=f"Win a {prize} today", 65 | colour=0x00FFFF) 66 | embed.add_field(name="Hosted By:", value=ctx.author.mention) 67 | embed.set_footer(text=f"Giveway ends in {answers[1]} from now") 68 | newMsg = await channel.send(embed=embed) 69 | await newMsg.add_reaction("🎉") 70 | #Check if Giveaway Cancelled 71 | self.cancelled = False 72 | await sleep(time) 73 | if not self.cancelled: 74 | myMsg = await channel.fetch_message(newMsg.id) 75 | 76 | users = await myMsg.reactions[0].users().flatten() 77 | users.pop(users.index(self.bot.user)) 78 | #Check if User list is not empty 79 | if len(users) <= 0: 80 | emptyEmbed = Embed(title="Giveaway Time !!", 81 | description=f"Win a {prize} today") 82 | emptyEmbed.add_field(name="Hosted By:", value=ctx.author.mention) 83 | emptyEmbed.set_footer(text="No one won the Giveaway") 84 | await myMsg.edit(embed=emptyEmbed) 85 | return 86 | if len(users) > 0: 87 | winner = choice(users) 88 | winnerEmbed = Embed(title="Giveaway Time !!", 89 | description=f"Win a {prize} today", 90 | colour=0x00FFFF) 91 | winnerEmbed.add_field(name=f"Congratulations On Winning {prize}", value=winner.mention) 92 | winnerEmbed.set_image(url="https://firebasestorage.googleapis.com/v0/b/sociality-a732c.appspot.com/o/Loli.png?alt=media&token=ab5c8924-9a14-40a9-97b8-dba68b69195d") 93 | await myMsg.edit(embed=winnerEmbed) 94 | return 95 | 96 | # @create_giveaway.error 97 | # async def create_giveaway_error(self, ctx, exc): 98 | # if isinstance(exc, MissingPermissions): 99 | # await ctx.send("You are not allowed to create Giveaways") 100 | 101 | 102 | @commands.command(name="giftrrl", aliases=["gifreroll", "gftroll", "grr"]) 103 | @has_permissions(manage_guild=True) 104 | # @has_role("admin") 105 | async def giveaway_reroll(self, ctx, channel : discord.TextChannel, id_: int): 106 | try: 107 | msg = await channel.fetch_message(id_) 108 | except: 109 | await ctx.send("The channel or ID mentioned was incorrect") 110 | users = await msg.reactions[0].users().flatten() 111 | if len(users) <= 0: 112 | emptyEmbed = Embed(title="Giveaway Time !!", 113 | description=f"Win a Prize today") 114 | emptyEmbed.add_field(name="Hosted By:", value=ctx.author.mention) 115 | emptyEmbed.set_footer(text="No one won the Giveaway") 116 | await msg.edit(embed=emptyEmbed) 117 | return 118 | if len(users) > 0: 119 | winner = choice(users) 120 | winnerEmbed = Embed(title="Giveaway Time !!", 121 | description=f"Win a Prize today", 122 | colour=0x00FFFF) 123 | winnerEmbed.add_field(name=f"Congratulations On Winning Giveaway", value=winner.mention) 124 | winnerEmbed.set_image(url="https://firebasestorage.googleapis.com/v0/b/sociality-a732c.appspot.com/o/Loli.png?alt=media&token=ab5c8924-9a14-40a9-97b8-dba68b69195d") 125 | await msg.edit(embed=winnerEmbed) 126 | return 127 | 128 | # users.pop(users.index(self.bot.user)) 129 | # winner = choice(users) 130 | # await channel.send(f"Congratulations {winner.mention} on winning the Giveaway") 131 | 132 | @commands.command(name="giftdel", aliases=["gifdel", "gftdel", "gdl"]) 133 | @has_permissions(manage_guild=True) 134 | # @has_role("admin") 135 | async def giveaway_stop(self, ctx, channel : discord.TextChannel, id_: int): 136 | try: 137 | msg = await channel.fetch_message(id_) 138 | newEmbed = Embed(title="Giveaway Cancelled", description="The giveaway has been cancelled!!") 139 | #Set Giveaway cancelled 140 | self.cancelled = True 141 | await msg.edit(embed=newEmbed) 142 | except: 143 | embed = Embed(title="Failure!", description="Cannot cancel Giveaway") 144 | await ctx.send(emebed=embed) 145 | 146 | 147 | @Cog.listener() 148 | async def on_ready(self): 149 | # await self.bot.stdout.send("Command Cog ready") 150 | if not self.bot.ready: 151 | self.bot.command_ready.ready_up("giveaway") 152 | 153 | def setup(bot): 154 | bot.add_cog(Giveaway(bot)) -------------------------------------------------------------------------------- /Python/Cogs/giveaway/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord 2 | asyncio 3 | -------------------------------------------------------------------------------- /Python/Cogs/giveaway/util.py: -------------------------------------------------------------------------------- 1 | def convert(time): 2 | pos = ["s","m","h","d"] 3 | time_dict = {"s": 1,"m": 60,"h": 3600,"d": 24*3600 } 4 | unit = time[-1] 5 | if unit not in pos: 6 | return -1 7 | try: 8 | timeVal = int(time[:-1]) 9 | except: 10 | return -2 11 | 12 | return timeVal*time_dict[unit] -------------------------------------------------------------------------------- /Python/Cogs/tictactoe/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord -------------------------------------------------------------------------------- /Python/Cogs/tictactoe/tic_tac_toe.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import discord 4 | from discord.ext import commands 5 | 6 | 7 | # Defines a custom button that contains the logic of the game. 8 | # The ['TicTacToe'] bit is for type hinting purposes to tell your IDE or linter 9 | # what the type of `self.view` is. It is not required. 10 | class TicTacToeButton(discord.ui.Button["TicTacToe"]): 11 | def __init__(self, x: int, y: int): 12 | # A label is required, but we don't need one so a zero-width space is used 13 | # The row parameter tells the View which row to place the button under. 14 | # A View can only contain up to 5 rows -- each row can only have 5 buttons. 15 | # Since a Tic Tac Toe grid is 3x3 that means we have 3 rows and 3 columns. 16 | super().__init__(style=discord.ButtonStyle.secondary, label="\u200b", row=y) 17 | self.x = x 18 | self.y = y 19 | 20 | # This function is called whenever this particular button is pressed 21 | # This is part of the "meat" of the game logic 22 | async def callback(self, interaction: discord.Interaction): 23 | assert self.view is not None 24 | view: TicTacToe = self.view 25 | state = view.board[self.y][self.x] 26 | if state in (view.X, view.O): 27 | return 28 | 29 | if view.current_player == view.X: 30 | self.style = discord.ButtonStyle.danger 31 | self.label = "X" 32 | self.disabled = True 33 | view.board[self.y][self.x] = view.X 34 | view.current_player = view.O 35 | content = "It is now O's turn" 36 | else: 37 | self.style = discord.ButtonStyle.success 38 | self.label = "O" 39 | self.disabled = True 40 | view.board[self.y][self.x] = view.O 41 | view.current_player = view.X 42 | content = "It is now X's turn" 43 | 44 | winner = view.check_board_winner() 45 | if winner is not None: 46 | if winner == view.X: 47 | content = "X won!" 48 | elif winner == view.O: 49 | content = "O won!" 50 | else: 51 | content = "It's a tie!" 52 | 53 | for child in view.children: 54 | child.disabled = True 55 | 56 | view.stop() 57 | 58 | await interaction.response.edit_message(content=content, view=view) 59 | 60 | 61 | # This is our actual board View 62 | class TicTacToe(discord.ui.View): 63 | # This tells the IDE or linter that all our children will be TicTacToeButtons 64 | # This is not required 65 | children: List[TicTacToeButton] 66 | X = -1 67 | O = 1 68 | Tie = 2 69 | 70 | def __init__(self): 71 | super().__init__() 72 | self.current_player = self.X 73 | self.board = [ 74 | [0, 0, 0], 75 | [0, 0, 0], 76 | [0, 0, 0], 77 | ] 78 | 79 | # Our board is made up of 3 by 3 TicTacToeButtons 80 | # The TicTacToeButton maintains the callbacks and helps steer 81 | # the actual game. 82 | for x in range(3): 83 | for y in range(3): 84 | self.add_item(TicTacToeButton(x, y)) 85 | 86 | # This method checks for the board winner -- it is used by the TicTacToeButton 87 | def check_board_winner(self): 88 | for across in self.board: 89 | value = sum(across) 90 | if value == 3: 91 | return self.O 92 | elif value == -3: 93 | return self.X 94 | 95 | # Check vertical 96 | for line in range(3): 97 | value = self.board[0][line] + self.board[1][line] + self.board[2][line] 98 | if value == 3: 99 | return self.O 100 | elif value == -3: 101 | return self.X 102 | 103 | # Check diagonals 104 | diag = self.board[0][2] + self.board[1][1] + self.board[2][0] 105 | if diag == 3: 106 | return self.O 107 | elif diag == -3: 108 | return self.X 109 | 110 | diag = self.board[0][0] + self.board[1][1] + self.board[2][2] 111 | if diag == 3: 112 | return self.O 113 | elif diag == -3: 114 | return self.X 115 | 116 | # If we're here, we need to check if a tie was made 117 | if all(i != 0 for row in self.board for i in row): 118 | return self.Tie 119 | 120 | return None 121 | 122 | 123 | class TicTacToeBot(commands.Bot): 124 | def __init__(self): 125 | super().__init__(command_prefix=commands.when_mentioned_or("$")) 126 | 127 | async def on_ready(self): 128 | print(f"Logged in as {self.user} (ID: {self.user.id})") 129 | print("------") 130 | 131 | 132 | bot = TicTacToeBot() 133 | 134 | 135 | @bot.command() 136 | async def tic(ctx: commands.Context): 137 | """Starts a tic-tac-toe game with yourself.""" 138 | await ctx.send("Tic Tac Toe: X goes first", view=TicTacToe()) 139 | 140 | 141 | bot.run("token") 142 | -------------------------------------------------------------------------------- /Python/README.md: -------------------------------------------------------------------------------- 1 |

A Multipurpose bot with many Commands made using Pycord

2 |
3 |

If you want to contribute, join the Support server and raise a pull request

4 | 5 | 6 |

STAR ⭐ THE PROJECT IF U LIKE

7 | 8 |

Categories 📑

9 | 10 | - ✅ Tic tac toe with buttons 11 | - ✅ Music 12 | - ✅ Moderation 13 | - ✅ Info 14 | - ✅ giveaway 15 | - ✅ fun 16 | - ✅ Paginator 17 | - ✅ Meme 18 | - ✅ search 19 | - ✅ economy 20 | - ✅ Search 21 | - ✅ Poll 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | ### STAR THE PROJECT IF U LIKE :) 31 | -------------------------------------------------------------------------------- /Python/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Use this section to tell people how to report a vulnerability. 6 | 7 | If you want to report a vulnerability, there are 2 ways. 8 | 9 | You can open an issue, 10 | or raise a pull request. 11 | -------------------------------------------------------------------------------- /Python/global-req.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Pycord-Development/pycord 2 | asyncio 3 | youtube-dl 4 | pynacl 5 | FFmpeg 6 | google 7 | beautifulsoup4 8 | asyncpraw 9 | aiohttp 10 | -------------------------------------------------------------------------------- /Python/main.py: -------------------------------------------------------------------------------- 1 | import discord 2 | from discord.ext import commands 3 | import os 4 | 5 | TOKEN = os.environ['TOKEN'] 6 | intents = discord.Intents.all() #need to enable 7 | bot = commands.Bot(command_prefix='~', intents=intents) 8 | 9 | for foldername in os.listdir('./Cogs'): #for every folder in cogs 10 | for filename in os.listdir(f'./Cogs/{foldername}'):# for every file in a folder in cogs 11 | if filename.endswith('.py') and not filename in ['util.py', 'error.py']: #if the file is a python file and if the file is a cog 12 | bot.load_extension(f'Cogs.{foldername}.{filename[:-3]}')#load the extension 13 | 14 | 15 | 16 | bot.run(TOKEN) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

A Multipurpose bot with many Commands.

2 |
If you want to contribute, join the Support server and raise a pull request
3 | 4 | # How to use this repo: 5 | Note: If you want to use the code in this repo, do NOT fork it. this repo has JS and Python versions of the same bot, so I fail to understand how will this be usefull if you fork it. 6 | 7 | ### Step 1: 8 | Navigate to any cog you want. 9 | Click on the "copy raw button" 10 | 11 | #### Video demonstration: 12 | ![Alt text](https://github.com/pogrammar/Discord-multipurpose-bot/blob/master/vids/Video%201.gif) 13 | 14 | 15 | ### Step 2: 16 | Hereafter, You need to replace any "..."'s or read the comments, if any customizing is required. 17 | 18 | 19 | -------------------------------------------------------------------------------- /vids/Video 1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pogrammar/Discord-multipurpose-bot/39139d75ac8048d9ff8c1c69c0ee1c230fed5b32/vids/Video 1.gif --------------------------------------------------------------------------------