diff --git a/.gitignore b/.gitignore
index aa99829..7802799 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,7 @@
.idea/
+
+*.pyc
+/logs/
+
.env
__pycache__/
\ No newline at end of file
diff --git a/README.md b/README.md
index d720813..e649712 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,6 @@
DecodED 3
-> ๐ Hello and welcome to DecodED 3! Over the next 6 weeks, we will be creating a discord bot with [Discord.py](https://discordpy.readthedocs.io/en/stable/index.html)
-
-Demo
-
-* TODO add gif/screenshot of Discord bot in action
+> ๐ Hello and welcome to DecodED 3! Over the next 5 weeks, we will be creating a discord bot with [Discord.py](https://discordpy.readthedocs.io/en/stable/index.html)
---
@@ -14,27 +10,31 @@
- [About DecodED](#about-decoded)
- [Dates](#dates)
+ - [Zoom Link: https://unimelb.zoom.us/j/88528442813?pwd=WlYrQ3pHcm5xMXpGQkZZSllZZTNvQT09](#zoom-link-httpsunimelbzoomusj88528442813pwdwlyrq3phcm5xmxpgqkzzsllzztnvqt09)
- [About this repository](#about-this-repository)
- [Workshop 1 - Introduction to Discord.py](#workshop-1---introduction-to-discordpy)
-- [Workshop 2 - Tic Tac Toe](#workshop-2---tic-tac-toe)
-- [Workshop 3 - Polling Bot](#workshop-3---polling-bot)
-- [Workshop 4 - Meme Bot](#workshop-4---meme-bot)
-- [Workshop 5 - Music Bot](#workshop-5---music-bot)
+- [Workshop 2 - Meme Bot](#workshop-2---meme-bot)
+- [Workshop 3 - Music Bot](#workshop-3---music-bot)
+- [Workshop 4 - Polling Bot](#workshop-4---polling-bot)
+- [Workshop 5 - Tic Tac Toe](#workshop-5---tic-tac-toe)
---
## About DecodED
-* DecodED is a series of workshops run every year by HackMelbourne to help students/teach students with introductory programming background to/how to... TODO
-* This year we are trying a new teaching style with DecodED so let us know if you like it TODO add a feedback link
+
+* DecodED is a series of workshops run every year by HackMelbourne to help students/teach students with introductory
+ programming background to create some cool things with code. In past years, we created full-stack websites and a Space Invaders game. This year, we will be creating a Discord bot!
+* We are also trying a new teaching style this year so let us know if you like it!
+
### Dates
Lesson | Location | People | Date
| -- | -- | -- | -- |
-Foundations (Basic) | Alan Gilbert 101 and Zoom | Xin Yu | 2pm, Wednesday 24th August
-Meme bot (easy) | Alan Gilbert G20 and Zoom | Aly, Minh | Wednesday 31st August
-Music bot | Alan Gilbert 121 (Theatre) and Zoom | Aryan, Ryan | Wednesday 7th September
+Foundations (Basic) | Alan Gilbert 101 and Zoom | Xin Yu | 2pm, Wednesday 24th August
+Meme bot (easy) | Zoom | Aly, Minh | Wednesday 31st August
+Music bot | Alan Gilbert 121 (Theatre) and Zoom | Aryan, Ryan | Wednesday 7th September
Poll | Alan Gilbert G20 and Zoom | Jerry, Hoan | Wednesday 14th September
TicTacToe bot | Alan Gilbert 103 and Zoom | Warren, Daniel | 2pm, Wednesday 21st September
@@ -44,41 +44,59 @@ Password: 323737
## About this repository
* This repository contains:
* Participant Workbook
- * each workbook is made up of multiple Parts which are then made up of multiple **โ
Tasks** that the participant should complete, with **๐งฉ Hints** that help guide them in completing the Task, and **๐ก Extensions** that are optional tasks that can be done if the participant has completed the Task ahead of schedule
- * The flow:
- 1. host presents/teaches about Part 1
- 2. participants follow the workbook to complete the โ
Tasks in Part 1 of the workbook - participants who are ahead of the tasks can start do the ๐ก Extensions and participants who are behind can use the ๐งฉ Hints or ask for help
- 3. once most of the participants are done with Part 1, host starts presenting/teaching Part 2 and the cycle continues
- * Slides (if any)
+ * each workbook is made up of multiple Parts which are then made up of multiple **โ
Tasks** that the participant
+ should complete, with **๐งฉ Hints** that help guide them in completing the Task, and **๐ก Extensions** that are
+ optional tasks that can be done if the participant has completed the Task ahead of schedule
* Workshop Recordings
* Code for the Discord Bot being created
## Workshop 1 - Introduction to Discord.py
-> About DecodED3, Covers basics of Discord.py, create a basic bot that says "Hello, World!", learn about the basic structure of bots,
-* [๐Participant Workbook](/w1/README.md)
-* [๐Python Cheatsheet](/w1/python_cheatsheet.md)
-* [๐Python Setup](/w1/python_setup.md)
-* [๐พDiscord.py Cheatsheet](/w1/discord_py_cheatsheet.md)
-* [๐Discord.py Documentation](https://discordpy.readthedocs.io/en/stable/index.html)
-* [Workshop Recording] TBD!
+
+> About DecodED3, Covers basics of Discord.py, create a basic bot that says "Hello, World!", learn about the basic
+> structure of Discord bots.
+>
+> Hosted by Xin Yu
+
+* [๐Participant Workbook](https://github.com/HackMelbourne/Decoded-3/tree/foundations-bot)
+* [Workshop Recording] Coming Soon!
## Workshop 2 - Meme Bot
-> Who doesnโt love a good meme? Join us and create the functionality to meme on your friends so hard that they wished they had their own meme bot.
-* Aly and Minh
+
+> Who doesnโt love a good meme? Join us and create the functionality to meme on your friends so hard that they wished
+> they had their own meme bot.
+>
+> Hosted by Aly and Minh
+
+* [๐Participant Workbook](https://github.com/HackMelbourne/Decoded-3/tree/meme_bot)
+* [Workshop Recording]
## Workshop 3 - Music Bot
-> Ever since YouTube banned music bots, discord servers have been desperately lacking some tunes. Impress your friends by bringing them back by building your own bot with the ability to play music, plus additional music controls! Now you can resume your lo-fi beat study sessions with your mates!
-* Aryan and Ryan
+> Ever since YouTube banned music bots, discord servers have been desperately lacking some tunes. Impress your friends
+> by bringing them back by building your own bot with the ability to play music, plus additional music controls! Now you
+> can resume your lo-fi beat study sessions with your mates!
+>
+> Hosted by Aryan and Ryan
+
+* [๐Participant Workbook](https://github.com/HackMelbourne/Decoded-3/tree/music-bot)
+* [Workshop Recording]
## Workshop 4 - Polling Bot
-> Caught up in your server arguing why Minecraft is (definitively) the best game? Why not run a poll on your server and prove your friends wrong? Learn to build your own polling bot to settle your arguments in style ๐
-* Jerry and Hoan
+> Caught up in your server arguing why Minecraft is (definitively) the best game? Why not run a poll on your server and
+> prove your friends wrong? Learn to build your own polling bot to settle your arguments in style ๐
+>
+> Jerry and Hoan
-## Workshop 5 - Tic Tac Toe
-> Fancy a game, but donโt want to leave your friends in discord? In this lesson, youโll learn to implement a tic tac toe game within the Discord bot so you can vs your friends whenever you wish!
+* [๐Participant Workbook](https://github.com/HackMelbourne/Decoded-3/tree/poll_system)
+* [Workshop Recording]
-* Warren and Weng Jae (Daniel)
+## Workshop 5 - Tic Tac Toe
+> Fancy a game, but donโt want to leave your friends in discord? In this lesson, youโll learn to implement a tic tac toe
+> game within the Discord bot so you can vs your friends whenever you wish!
+>
+> Warren and Weng Jae (Daniel)
+* [๐Participant Workbook](https://github.com/HackMelbourne/Decoded-3/tree/tictactoe)
+* [Workshop Recording]
\ No newline at end of file
diff --git a/cogless.py b/cogless.py
new file mode 100644
index 0000000..3edde1d
--- /dev/null
+++ b/cogless.py
@@ -0,0 +1,22 @@
+import discord
+import os
+
+from dotenv import load_dotenv
+load_dotenv()
+TOKEN = os.getenv('TOKEN')
+
+client = discord.Client(intents=discord.Intents.all())
+
+@client.event
+async def on_ready():
+ print(f'We have logged in as {client.user}')
+
+@client.event
+async def on_message(msg):
+ # print(msg.content)
+ if msg.author == client.user:
+ return
+ if msg.content.startswith('$hello'):
+ await msg.channel.send(f'Hello, {msg.author.name}!')
+
+client.run(TOKEN)
diff --git a/cogs/hello.py b/cogs/hello.py
index 9cbe5d2..fbc03ac 100644
--- a/cogs/hello.py
+++ b/cogs/hello.py
@@ -1,18 +1,18 @@
from discord.ext import commands
-class Hello(commands.Cog):
+
+class Hello(commands.Cog): # ๐ cog class called `Hello`
def __init__(self, client):
- self.client = client # defining bot as global var in class
+ self.client = client
- @commands.Cog.listener() # this is a decorator for events/listeners
+ @commands.Cog.listener() # ๐ this is a decorator for events/listeners
async def on_ready(self):
print(f'We have logged in as {self.client.user}')
-
- @commands.command() # this is for making a command
- async def hello(self, ctx):
- print(ctx)
+ @commands.command() # this is for making a command
+ async def hello(self, ctx): # ๐ called when messages contain `!hello`
await ctx.send(f'Hi!')
-
-def setup(bot): # a extension must have a setup function
- bot.add_cog(Hello(bot)) # adding a cog
\ No newline at end of file
+
+
+async def setup(bot): # ๐ a extension must have a setup function
+ await bot.add_cog(Hello(bot)) # ๐ adding the cog
\ No newline at end of file
diff --git a/cogs/meme.py b/cogs/meme.py
new file mode 100644
index 0000000..530fae1
--- /dev/null
+++ b/cogs/meme.py
@@ -0,0 +1,152 @@
+import json
+import os
+
+import requests
+from discord.ext import commands
+from dotenv import load_dotenv
+from pymongo import MongoClient
+from requests.exceptions import HTTPError
+from schema import Schema, SchemaError, And, Regex
+
+load_dotenv()
+
+TOKEN = os.getenv('TOKEN')
+COMMAND = os.getenv('DISCORD_COMMAND_ROOT')
+BOTNAME = os.getenv('BOT_NAME')
+API_ROOT = os.getenv('MEME_API_ROOT')
+MONGODB_URI = os.getenv('MONGODB_URI')
+DB = os.getenv('DB')
+COLLECTION = os.getenv('COLLECTION')
+
+collection = MongoClient(MONGODB_URI)[DB][COLLECTION]
+
+
+# all commands that this bot will respond to will begin with ";;bot_name"
+# bot = commands.Bot(command_prefix=COMMAND + BOTNAME, strip_after_prefix=True, intents=discord.Intents.all())
+
+def get_random_memes(count):
+ try:
+ response = requests.get(f"{API_ROOT}{count}")
+ except HTTPError as error:
+ raise error
+ json_data = json.loads(response.text)
+ return json_data
+
+
+def get_random_meme_from_subreddits(subReddit, count):
+ try:
+ response = requests.get(f"{API_ROOT}{subReddit}/{count}")
+ except HTTPError as error:
+ raise error
+ if (response.status_code == 404 or response.status_code == 400):
+ raise HTTPError(response.text)
+ json_data = json.loads(response.text)
+ return json_data
+
+
+def check_link_die(link):
+ try:
+ response = requests.get(link)
+ except:
+ return False
+ if (response.status_code == 404):
+ return False
+ return True
+
+
+meme_schema = Schema({
+ "name": str,
+ "url": And(str, Regex("^(https:\/\/i.redd.it\/)\w+\.\w{3}$"))})
+
+
+class Meme(commands.Cog):
+ def __init__(self, bot):
+ self.bot = bot
+
+ @commands.command()
+ async def meme(self, ctx, *args):
+ # ;;random
+ if (len(args) == 0):
+ random_meme = get_random_memes(1)['memes'][0]
+ while (check_link_die(random_meme['url']) == False):
+ random_meme = get_random_memes(1)['memes'][0]
+ await ctx.send(random_meme['url'])
+
+ # ;;random 5
+ if (len(args) > 0):
+ try:
+ random_memes = get_random_memes(int(args[0]))['memes']
+ except:
+ await ctx.send("Unrecognized command. Pretty sure that wasn't a number :)")
+ pass
+ random_memes_image_link = [e['url'] for e in random_memes]
+ for link in random_memes_image_link:
+ if (check_link_die(link) == False):
+ continue
+ else:
+ await ctx.send(link)
+ pass
+
+ @commands.command()
+ async def meme_subreddit(self, ctx, arg1):
+ subreddit = arg1
+ try:
+ random_meme = get_random_meme_from_subreddits(subreddit, 1)
+ random_meme_subreddit = random_meme['memes'][0]
+ while (check_link_die(random_meme_subreddit['url']) == False):
+ random_meme = get_random_meme_from_subreddits(subreddit, 1)
+ random_meme_subreddit = random_meme['memes'][0]
+ await ctx.send(random_meme_subreddit['url'])
+ except HTTPError as err:
+ await ctx.send('Subreddit not found')
+ pass
+ pass
+
+ @commands.command()
+ async def save_meme(self, ctx, arg1):
+ try:
+ response = await ctx.channel.fetch_message(ctx.message.reference.message_id)
+ meme_url = response.content
+ except print(0):
+ await ctx.send("You forgot to reply to a meme, or the meme you replied to wasn't saved in the right format")
+ pass
+ saved_name = arg1
+ saved_meme = {
+ "name": saved_name,
+ "url": meme_url,
+ }
+ try:
+ meme_schema.validate(saved_meme)
+ except SchemaError as err:
+ await ctx.send(err)
+ pass
+ collection.insert_one(saved_meme)
+ await ctx.send("Saved to database!")
+ pass
+
+ @commands.command()
+ async def load_meme(self, ctx, arg1):
+ lookup_name = arg1
+ try:
+ found_meme = collection.find_one({"name": lookup_name})
+ await ctx.send(found_meme["url"])
+ except TypeError:
+ await ctx.send("Meme not found in database!")
+ pass
+ pass
+
+ @commands.command()
+ async def delete_meme(self, ctx, arg1):
+ lookup_name = arg1
+ try:
+ found_meme = collection.find_one({"name": lookup_name})
+ except TypeError:
+ await ctx.send("Meme not found in database!")
+ pass
+ collection.delete_one(found_meme)
+ await ctx.send("Meme was deleted from database!")
+ pass
+
+
+async def setup(bot):
+ await bot.add_cog(Meme(bot))
diff --git a/main.py b/main.py
index 04aed33..424e4ce 100644
--- a/main.py
+++ b/main.py
@@ -1,22 +1,17 @@
-import discord
import os
-
from dotenv import load_dotenv
+from discord.ext import commands
+import discord
+import asyncio
+
load_dotenv()
TOKEN = os.getenv('TOKEN')
-client = discord.Client()
-
-@client.event
-async def on_ready():
- print(f'We have logged in as {client.user}')
+client = commands.Bot(command_prefix = "!", intents = discord.Intents.all()) # instead of a client, we create a Bot instance
-@client.event
-async def on_message(msg):
- # print(msg.content)
- if msg.author == client.user:
- return
- if msg.content.startswith('$hello'):
- await msg.channel.send(f'Hello, {msg.author.name}!')
+# ๐ Looks inside the /cogs/ folder and loads up all of our cogs
+for filename in os.listdir("./cogs"):
+ if filename.endswith(".py"):
+ asyncio.run(client.load_extension("cogs." + filename[:-3])) # calls the cog's `setup()` function
-client.run(TOKEN)
+client.run(TOKEN)
\ No newline at end of file
diff --git a/main2.py b/main2.py
deleted file mode 100644
index 8d85721..0000000
--- a/main2.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# main.py
-from discord.ext import commands
-import os
-from dotenv import load_dotenv
-
-load_dotenv()
-TOKEN = os.getenv('TOKEN')
-
-client = commands.Bot(command_prefix = "!")
-
-# Looks inside the /cogs/ folder and loads up all of our cogs
-for filename in os.listdir("./cogs"):
- if filename.endswith(".py"):
- client.load_extension("cogs." + filename[:-3])
-
-client.run(TOKEN)
diff --git a/src/main.py b/src/main.py
deleted file mode 100644
index 53f597e..0000000
--- a/src/main.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# TODO move to cogs folder
-from pymongo import MongoClient
-import os
-from dotenv import load_dotenv
-import discord
-from discord.ext import commands
-import requests
-from requests.exceptions import HTTPError
-import json
-from schema import Schema, SchemaError, And, Regex
-
-load_dotenv()
-
-TOKEN = os.getenv('DISCORD_TOKEN')
-GUILD = os.getenv('DISCORD_GUILD')
-COMMAND = os.getenv('DISCORD_COMMAND_ROOT')
-BOTNAME = os.getenv('BOT_NAME')
-API_ROOT = os.getenv('MEME_API_ROOT')
-MONGODB_URI = os.getenv('MONGODB_URI')
-DB = os.getenv('DB')
-COLLECTION = os.getenv('COLLECTION')
-
-collection = MongoClient(MONGODB_URI)[DB][COLLECTION]
-
-# all commands that this bot will respond to will begin with ";;bot_name"
-bot = commands.Bot(command_prefix=COMMAND + BOTNAME, strip_after_prefix=True)
-
-
-def get_random_memes(count):
- try:
- response = requests.get(f"{API_ROOT}{count}")
- except HTTPError as error:
- raise error
- json_data = json.loads(response.text)
- return json_data
-
-
-def get_random_meme_from_subreddits(subReddit, count):
- try:
- response = requests.get(f"{API_ROOT}{subReddit}/{count}")
- except HTTPError as error:
- raise error
- if(response.status_code == 404 or response.status_code == 400):
- raise HTTPError(response.text)
- json_data = json.loads(response.text)
- return json_data
-
-
-def check_link_die(link):
- try:
- response = requests.get(link)
- except:
- return False
- if(response.status_code == 404):
- return False
- return True
-
-
-meme_schema = Schema({
- "name": str,
- "url": And(str, Regex("^(https:\/\/i.redd.it\/)\w+\.\w{3}$"))})
-
-
-@commands.command(name='new')
-async def _new(ctx, *args):
- # ;;random
- if (len(args) == 0):
- random_meme = get_random_memes(1)['memes'][0]
- while(check_link_die(random_meme['url']) == False):
- random_meme = get_random_memes(1)['memes'][0]
- await ctx.send(random_meme['url'])
-
- # ;;random 5
- if (len(args) > 0):
- try:
- random_memes = get_random_memes(int(args[0]))['memes']
- except:
- await ctx.send("Unrecognized command. Pretty sure that wasn't a number :)")
- pass
- random_memes_image_link = [e['url'] for e in random_memes]
- for link in random_memes_image_link:
- if(check_link_die(link) == False):
- continue
- else:
- await ctx.send(link)
- pass
-bot.add_command(_new)
-
-
-@commands.command(name='subreddit')
-async def _subreddit(ctx, arg1):
- subreddit = arg1
- try:
- random_meme = get_random_meme_from_subreddits(subreddit, 1)
- random_meme_subreddit = random_meme['memes'][0]
- while(check_link_die(random_meme_subreddit['url']) == False):
- random_meme = get_random_meme_from_subreddits(subreddit, 1)
- random_meme_subreddit = random_meme['memes'][0]
- await ctx.send(random_meme_subreddit['url'])
- except HTTPError as err:
- await ctx.send('Subreddit not found')
- pass
- pass
-bot.add_command(_subreddit)
-
-
-@commands.command(name='save')
-async def _save(ctx, arg1):
- try:
- response = await ctx.channel.fetch_message(ctx.message.reference.message_id)
- meme_url = response.content
- except print(0):
- await ctx.send("You forgot to reply to a meme, or the meme you replied to wasn't saved in the right format")
- pass
- saved_name = arg1
- saved_meme = {
- "name": saved_name,
- "url": meme_url,
- }
- try:
- meme_schema.validate(saved_meme)
- except SchemaError as err:
- await ctx.send(err)
- pass
- collection.insert_one(saved_meme)
- await ctx.send("Saved to database!")
- pass
-bot.add_command(_save)
-
-
-@commands.command(name='load')
-async def _load(ctx, arg1):
- lookup_name = arg1
- try:
- found_meme = collection.find_one({"name": lookup_name})
- await ctx.send(found_meme["url"])
- except TypeError:
- await ctx.send("Meme not found in database!")
- pass
- pass
-bot.add_command(_load)
-
-
-@commands.command(name='delete')
-async def _delete(ctx, arg1):
- lookup_name = arg1
- try:
- found_meme = collection.find_one({"name": lookup_name})
- found_meme["url"]
- except TypeError:
- await ctx.send("Meme not found in database!")
- pass
- collection.delete_one(found_meme)
- await ctx.send("Meme was deleted from database!")
- pass
-bot.add_command(_delete)
-
-bot.run(TOKEN)
diff --git a/w1/README.md b/w1/README.md
index b661b06..d327105 100644
--- a/w1/README.md
+++ b/w1/README.md
@@ -1,7 +1,5 @@
[Participant's Workbook] Introduction to Discord.py
-> Related Pages: [DecodED 3](./README.md)
-
---
Table of Contents
@@ -45,13 +43,13 @@
### โ
Task: Create a Discord Account
> ๐ NOTE: If you already have a Discord account, you can skip this task
* You can register for a Discord account [here](https://discord.com/register).
- * ![](2022-08-06-16-47-20.png)
+ * ![](./images/2022-08-06-16-47-20.png)
### โ
Task: Create a Discord Server
> ๐ NOTE: Discord servers are sometimes refered to as **'guilds'** in some documentation (because some people confuse the word 'server' with computer servers ๐๏ธ XD)
* this server will be used for you to test your bot
* Follow Discord's documentation on [How do I create a server?](https://support.discord.com/hc/en-us/articles/204849977-How-do-I-create-a-server-)
1. Click on the "+" button at the bottom of the left hand column on Discord
- * ![](2022-08-06-16-52-41.png)
+ * ![](./images/2022-08-06-16-52-41.png)
2. Fill in the server details
* You can follow these options: Create My Own > For me and my friends > Name your server > "Create"
@@ -63,22 +61,22 @@
### โ
Task: Create a Discord Application and Bot, and copy your Token
* Login to the [Developer Portal's Applications Page](https://discord.com/developers/applications)
* Click on "New Application"
- * ![](2022-08-06-16-57-29.png)
+ * ![](./images/2022-08-06-16-57-29.png)
* Give the application a name and click "Create"
- * ![](2022-08-06-16-57-47.png)
+ * ![](./images/2022-08-06-16-57-47.png)
* Go to the "Bot" tab and then click "Add Bot" and "Yes, do it!"
- * ![](2022-08-06-17-01-31.png)
+ * ![](./images/2022-08-06-17-01-31.png)
* Now your bot has been created! Next step is to copy the token and paste it in a notepad or create a file called `.env` [(Environment Variables)](#environment-variables) and paste it in there for now
- * ![](2022-08-06-17-02-00.png)
+ * ![](./images/2022-08-06-17-02-00.png)
> ๐ NOTE: This token is your bot's password so don't share it with anybody. It could allow someone to log in to your bot and do all sorts of bad things.
>
> You are only able to see this token once (on the creation of the bot) but you can regenerate the token if it accidentally gets shared.
### โ
Task: Invite your bot to your server
* Go to the "OAuth2 > URL Generator" tab. Then select "bot" under the "scopes" section
- * ![](2022-08-06-17-11-00.png)
- * Now choose the permissions you want for the bot. For now, you can give it minimal permissions as we are making a simple bot but you might have to add more permissions as you progress through the other workshops and add more features!
- * ![](2022-08-06-17-11-30.png)
+ * ![](./images/2022-08-06-17-11-00.png)
+ * Now choose the permissions you want for the bot. You can either give it minimal permissions as we are making a simple bot for this workshop but might have to add more permissions as you progress through the other workshops and add more features or you could give it many permissions upfront and not have to worry about permissions later.
+ * ![](./images/2022-08-06-17-11-30.png)
* Then copy the generated URL, open it in a new tab and add your bot to your server.
> ๐ NOTE: Be careful when giving your bot "Administrator" permissions
@@ -95,7 +93,7 @@
* There are 2 ways to access the terminal in VS Code:
1. using the shortcut ```Ctrl + Shift + ` ```
2. Terminal > New Terminal
- * ![](vscode_access_terminal.gif)
+ * ![](./images/vscode_access_terminal.gif)
@@ -126,7 +124,7 @@
๐งฉ Creating Files in VS Code
-* ![](vscode_create_main_and_env_files.gif)
+* ![](./images/vscode_create_main_and_env_files.gif)
@@ -134,7 +132,9 @@
โ What are environment variables?
-> When a program is run, it may need information from the operating system to configure its behaviour. This might include the operating system, current running folder, or more important things like passwords to various services (Discord here!). Basically, environment variables are variables/information about the environment its running on. They are a useful tool in providing information to your program, which is separate from your code. Developers commonly use `.env` files to specify these variables.
+When a program is run, it may need information from the operating system to configure its behaviour. This might include the operating system, current running folder, or more important things like passwords to various services (Discord here!). Basically, environment variables are variables/information about the environment its running on. They are a useful tool in providing information to your program, which is separate from your code. Developers commonly use `.env` files to specify these variables.
+
+![](./images/1_BIgXzxgolWVDBNq5F_eZpg.png)
@@ -147,7 +147,7 @@
TOKEN=example.token.abc123
```
* [Replit] If you're using Replit to develop your bot, Replit does not let you create a `.env` file so go to the "Secrets" tab and create a key-value pair for your token
- * ![](2022-08-06-17-17-49.png)
+ * ![](./images/2022-08-06-17-17-49.png)
* Then in your code file:
```python
# ./main.py
@@ -175,7 +175,7 @@
* Then we create an instance of [`Client`](https://discordpy.readthedocs.io/en/stable/api.html#discord.Client), which is out connection to discord, and run it
```python
# ./main.py, after defining TOKEN
- client = discord.Client() # creates the bot
+ client = discord.Client(intents=discord.Intents.all()) # creates the bot
client.run(TOKEN) # runs the bot
```
@@ -188,37 +188,11 @@
๐ What are events and callbacks?
* **events**: actions or occurrences recognised by the program
- * eg. when the bot is done setting up and is ready to operate, when the
+ * eg. when the bot is done setting up and is ready to operate, when a message is sent, etc.
* **callback**: a function that is called when an event happens
* eg. the `on_ready()` event is called when the bot has finished logging in and setting things up
* to register an event, we use a decorator, `@client.event` on the callback function's definition
-
-
- ๐ What is async
and await
?
-
- Often in coding, you will need to perform a task, and wait for the response before you can do anything. An example would be Gmail, the website needs to wait for the mail to send, before telling you it's sent.
- Using `async` on a function lets Python know that this task involves waiting for something:
- ```python
- async def send_mail():
- await login()
- await send()
- ```
- and `await` tells Python to wait for an `async` function to finish before proceeding:
- ```python
- await send_mail()
- print("Your mail was sent!")
- # As opposed to
- send_mail()
- print("This will be printed immediately")
- ```
- In the context of discord.py, we can use `async` on our functions to tell discord.py it's going to do a long-running task, and `await` to do that task:
- ```python
- async def on_join(self, ctx):
- await ctx.send("Welcome to the server!")
- ```
- > ๐ More about asynchronous programming: [Getting Started With Async Features in Python | Real Python](https://realpython.com/python-async-features/)
-
```python
@@ -226,8 +200,6 @@
@client.event # ๐ this is a function decorator
async def on_ready(): # ๐ on_ready() is a callback
# code in on_ready() will be run after the bot is done logging in and setting up
-
- await message.channel.send("Hi")
```
### โ
Task: "Hello, World!"
@@ -241,8 +213,6 @@
> * `client.user.name`
> * `client.user.id`
> * try printing these `on_ready()`, what do these attributes store?
->
-> TODO "Navigating Documentation" (extra)
### Receiving Messages
* As said before, there are many events that we can register and 'listen' to. You can check out [Discord Docs > Event Reference](https://discordpy.readthedocs.io/en/stable/api.html#event-reference) for more events.
@@ -269,11 +239,36 @@
# ./main.py, in between defining the client and running it
@client.event
async def on_message(msg):
- if msg.author == client.user: # โ Question for participants: What is this if statement for?
+ if msg.author == client.user: # โ Question for participants: Why do you think we need this if statement?
return
await msg.channel.send("Good Morning!")
```
-* โ Question for participants: What is the `if` statement doing? Why do we need it? What happens if we remove it? (you might get a special prize if you answer this correctly!)
+
+ ๐ What is async
and await
?
+
+ Often in coding, you will need to perform a task, and wait for the response before you can do anything. An example would be Gmail, the website needs to wait for the mail to send, before telling you it's sent.
+ Using `async` on a function lets Python know that this task involves waiting for something:
+ ```python
+ async def send_mail():
+ await login()
+ await send()
+ ```
+ and `await` tells Python to wait for an `async` function to finish before proceeding:
+ ```python
+ await send_mail()
+ print("Your mail was sent!")
+ # As opposed to
+ send_mail()
+ print("This will be printed immediately")
+ ```
+ In the context of discord.py, we can use `async` on our functions to tell discord.py it's going to do a long-running task, and `await` to do that task:
+ ```python
+ async def on_join(self, ctx):
+ await ctx.send("Welcome to the server!")
+ ```
+ > ๐ More about asynchronous programming: [Getting Started With Async Features in Python | Real Python](https://realpython.com/python-async-features/)
+
+
### โ
Task: Respond to "!hello" with "Hello, {username}"
* Given that we know how to receive and send messages, try amending/adding some code in the `on_message()` to make your bot send "Hello, {username}" to anyone who sends messages starting with `$hello` (but replace {username} with the actual sender's username).
@@ -286,8 +281,6 @@
-> ๐ Don't hesitate to let us know you need any help!
-
---
## 5. Cogs
@@ -310,7 +303,7 @@
* Instead of a Client instance, we will create a Bot instance instead
```python
# ./main.py, replace `client = discord.Client()` with...
- client = commands.Bot(command_prefix = "!") # instead of a client, we create a Bot instance
+ client = commands.Bot(command_prefix = "!", intents = discord.Intents.all()) # instead of a client, we create a Bot instance
```
### โ
Task: Create a Hello Cog
* create a folder called `cogs`, this is where you will store your cogs
@@ -361,18 +354,20 @@
* this function will be called in `main.py`
```python
# ./cogs/hello.py, outside the Hello class
- def setup(bot): # ๐ a extension must have a setup function
- bot.add_cog(Hello(bot)) # ๐ adding the cog
+ async def setup(bot): # ๐ a extension must have a setup function
+ await bot.add_cog(Hello(bot)) # ๐ adding the cog
```
### โ
Task: Refactor `main.py` to support Cogs (part 2)
* Now, back in `main.py`, instead of having all of our bot's logic in the file, we have moved them into cogs that are located in the `./cogs` folder and now we should load up all of our cogs
```python
- # ./main.py, after defining the client
+ # ./main.py, with imports
+ import asyncio
+
# ๐ Looks inside the /cogs/ folder and loads up all of our cogs
for filename in os.listdir("./cogs"):
if filename.endswith(".py"):
- client.load_extension("cogs." + filename[:-3]) # calls the cog's `setup()` function
+ asyncio.run(client.load_extension("cogs." + filename[:-3])) # calls the cog's `setup()` function
client.run(TOKEN)
```
@@ -389,16 +384,11 @@
## 7. [๐ก Extension] Host your bot on Heroku
> this allows your bot to run continuously without having to open VSCode or keep your repl.it tab running
-* Create a Heroku Account
-*
-* ![](2022-07-27-20-48-43.png)
-* Choose an App name ()
- * ![](2022-07-27-20-50-00.png)
-* Once you're in your app's page, go over to your settings, scroll down to **Buildpack** and add the **Python** buildpack
- * ![](./deployment_add_buildpack.gif)
+
+* [Hosting your discord.py bot on Heroku](https://github.com/squid/discord-py-heroku)
+* [How to host a discord.py bot with Heroku and GitHub](https://medium.com/analytics-vidhya/how-to-host-a-discord-py-bot-on-heroku-and-github-d54a4d62a99e)
## Related Links:
* [Creating a Bot Account | discord.py](https://discordpy.readthedocs.io/en/stable/discord.html)
* [Python Discord Bot Tutorial โ Code a Discord Bot And Host it for Free | freeCodeCamp](https://www.freecodecamp.org/news/create-a-discord-bot-with-python/)
-* [Hosting your discord.py bot on Heroku](https://github.com/squid/discord-py-heroku)
-* [How to host a discord.py bot with Heroku and GitHub](https://medium.com/analytics-vidhya/how-to-host-a-discord-py-bot-on-heroku-and-github-d54a4d62a99e)
+
diff --git a/w1/discord_py_cheatsheet.md b/w1/discord_py_cheatsheet.md
deleted file mode 100644
index cba8b8f..0000000
--- a/w1/discord_py_cheatsheet.md
+++ /dev/null
@@ -1,6 +0,0 @@
-Discord.py CheatSheet
-
-## Events
-* Basic Structure of Event Callbacks
-```
-```
diff --git a/w1/images/1_BIgXzxgolWVDBNq5F_eZpg.png b/w1/images/1_BIgXzxgolWVDBNq5F_eZpg.png
new file mode 100644
index 0000000..2307a3b
Binary files /dev/null and b/w1/images/1_BIgXzxgolWVDBNq5F_eZpg.png differ
diff --git a/w1/2022-07-27-20-48-43.png b/w1/images/2022-07-27-20-48-43.png
similarity index 100%
rename from w1/2022-07-27-20-48-43.png
rename to w1/images/2022-07-27-20-48-43.png
diff --git a/w1/2022-07-27-20-50-00.png b/w1/images/2022-07-27-20-50-00.png
similarity index 100%
rename from w1/2022-07-27-20-50-00.png
rename to w1/images/2022-07-27-20-50-00.png
diff --git a/w1/2022-07-27-20-51-23.png b/w1/images/2022-07-27-20-51-23.png
similarity index 100%
rename from w1/2022-07-27-20-51-23.png
rename to w1/images/2022-07-27-20-51-23.png
diff --git a/w1/2022-08-06-16-47-20.png b/w1/images/2022-08-06-16-47-20.png
similarity index 100%
rename from w1/2022-08-06-16-47-20.png
rename to w1/images/2022-08-06-16-47-20.png
diff --git a/w1/2022-08-06-16-52-41.png b/w1/images/2022-08-06-16-52-41.png
similarity index 100%
rename from w1/2022-08-06-16-52-41.png
rename to w1/images/2022-08-06-16-52-41.png
diff --git a/w1/2022-08-06-16-57-29.png b/w1/images/2022-08-06-16-57-29.png
similarity index 100%
rename from w1/2022-08-06-16-57-29.png
rename to w1/images/2022-08-06-16-57-29.png
diff --git a/w1/2022-08-06-16-57-47.png b/w1/images/2022-08-06-16-57-47.png
similarity index 100%
rename from w1/2022-08-06-16-57-47.png
rename to w1/images/2022-08-06-16-57-47.png
diff --git a/w1/2022-08-06-17-01-31.png b/w1/images/2022-08-06-17-01-31.png
similarity index 100%
rename from w1/2022-08-06-17-01-31.png
rename to w1/images/2022-08-06-17-01-31.png
diff --git a/w1/2022-08-06-17-02-00.png b/w1/images/2022-08-06-17-02-00.png
similarity index 100%
rename from w1/2022-08-06-17-02-00.png
rename to w1/images/2022-08-06-17-02-00.png
diff --git a/w1/2022-08-06-17-05-59.png b/w1/images/2022-08-06-17-05-59.png
similarity index 100%
rename from w1/2022-08-06-17-05-59.png
rename to w1/images/2022-08-06-17-05-59.png
diff --git a/w1/2022-08-06-17-11-00.png b/w1/images/2022-08-06-17-11-00.png
similarity index 100%
rename from w1/2022-08-06-17-11-00.png
rename to w1/images/2022-08-06-17-11-00.png
diff --git a/w1/2022-08-06-17-11-30.png b/w1/images/2022-08-06-17-11-30.png
similarity index 100%
rename from w1/2022-08-06-17-11-30.png
rename to w1/images/2022-08-06-17-11-30.png
diff --git a/w1/2022-08-06-17-17-22.png b/w1/images/2022-08-06-17-17-22.png
similarity index 100%
rename from w1/2022-08-06-17-17-22.png
rename to w1/images/2022-08-06-17-17-22.png
diff --git a/w1/2022-08-06-17-17-49.png b/w1/images/2022-08-06-17-17-49.png
similarity index 100%
rename from w1/2022-08-06-17-17-49.png
rename to w1/images/2022-08-06-17-17-49.png
diff --git a/w1/deployment_add_buildpack.gif b/w1/images/deployment_add_buildpack.gif
similarity index 100%
rename from w1/deployment_add_buildpack.gif
rename to w1/images/deployment_add_buildpack.gif
diff --git a/w1/vscode_access_terminal.gif b/w1/images/vscode_access_terminal.gif
similarity index 100%
rename from w1/vscode_access_terminal.gif
rename to w1/images/vscode_access_terminal.gif
diff --git a/w1/vscode_create_main_and_env_files.gif b/w1/images/vscode_create_main_and_env_files.gif
similarity index 100%
rename from w1/vscode_create_main_and_env_files.gif
rename to w1/images/vscode_create_main_and_env_files.gif