Discord Bot
lecturer: 乘一
~雜七雜八
基本架構
Bot基本架構
import discord #導入 Discord.py
from discord.ext import commands #導入 commands 雖然目前不會用到
import os #導入os模組
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='你想要的指令前綴', intents = intents)
#透過bot與dicord連結,並設定command的前綴(但還不會用到)
@bot.event #這是裝飾器
async def on_ready(): #當機器人完成啟動時
print('目前登入身份:', bot.user)
try:
bot.run('機器人TOKEN') #就是你剛剛拿到的TOKEN
except:
os.system("kill 1") #修正程式錯誤(repl會莫名其妙出錯)
Event
Event
#當...的時候要做甚麼->event!
@bot.event #裝飾器
async def function_name(parameters):
#async 異步協程
...
Event
Command
Command
@bot.event
async def on_message(msg):
await bot.process_commands(msg)
#解決on_message 與 command 衝突的問題
@bot.command()
async def command_name(ctx):
#ctx上下文
#包含各種訊息,如:發送者、頻道...
#...
Cog
Cog 是啥?
Bot.py
on_message
on_member
ping
Cog 是啥?
Bot.py
on_message
on_member
ping
Event.py
cmd.py
Cog 是啥?
Bot.py
on_message
on_member
ping
Event.py
cmd.py
Cog 是啥?
Bot.py
on_message
on_member
ping
Event.py
cmd.py
load
Cog
先分開再說
Cog
Command
#原本
import discord
from discord.ext import commands
@bot.command()
async def ping(ctx):
await ctx.send(f'{round(bot.latency*1000, 2)}ms')
Command
#改成cog
import discord
from discord.ext import commands
class Cmd(commands.Cog): #繼承commands.Cog
def __init__(self, bot):
self.bot = bot
@commands.command() #記得改
async def ping(self, ctx): #記得加self
await ctx.send(f'{round(self.bot.latency*1000, 2)}ms')
async def setup(bot):
await bot.add_cog(Cmd(bot))
Event
#原本event
import discord #導入 Discord.py
from discord.ext import commands
import asyncio
@bot.event
async def on_message(msg): #當偵測到訊息
if msg.author == bot.user: #避免無限循環
return
if msg.content.startswith("say"): #偵測msg的開頭
await msg.channel.send("hello")
Event
#改成cog
import discord
from discord.ext import commands
import asyncio
class Event(commands.Cog): #繼承commands.Cog
def __init__(self, bot):
self.bot = bot
@commands.Cog.listener() #改
async def on_message(self, msg): #記得加self
if msg.author == self.bot.user: #避免無限循環
return
if msg.content.startswith("say"): #偵測msg的開頭
await msg.channel.send("hello!")
async def setup(bot):
await bot.add_cog(Event(bot))
Main
import discord #導入 Discord.py
from discord.ext import commands
import os #導入os模組
import asyncio
intents = discord.Intents.all()
bot = commands.Bot(command_prefix='(', intents=intents)
@bot.event #這是裝飾器
async def on_ready(): #當機器人完成啟動時
print('目前登入身份:', bot.user)
@bot.command()
async def load(ctx, ext):
await bot.load_extension(f'cogs.{ext}')
await ctx.send(f'{ext} loaded successfully.')
@bot.command()
async def unload(ctx, ext):
await bot.unload_extension(f'cogs.{ext}')
await ctx.send(f'{ext} unloaded successfully.')
@bot.command()
async def reload(ctx, ext):
await bot.reload_extension(f'cogs.{ext}')
await ctx.send(f'{ext} reloaded successfully.')
async def load_extensions(): #一開始要把所有cog載入
for filename in os.listdir("./cogs"):
if filename.endswith(".py"): #偵測有py的檔案
await bot.load_extension(f"cogs.{filename[:-3]}") #去除.py
async def main():
async with bot:
await load_extensions()
await bot.start(os.getenv("TOKEN"))
if __name__ == "__main__": #如果跑的是這個py
try:
asyncio.run(main()) #就是你剛剛拿到的TOKEN
except:
os.system("kill 1") #修正程式錯誤(repl會莫名其妙出錯)
Classes.py
import discord #導入 Discord.py
from discord.ext import commands
class Cog_Extension(commands.Cog):
def __init__(self, bot):
self.bot = bot
Classes.py
#每個檔案都要繼承?
class Filename(commands.Cog):
def __init__(self, bot):
self.bot = bot
簡化!
#把重複的東東放到classes.py
#用的時候繼承class就好了
from core.classes import Cog_Extension
class Filename(Cog_Extension):
Uptime Robot
終於要開始上課了
repl.it 會自動斷線!??
當你把你的bot放在repl.it上面開始跑
然後睡一覺起來之後...
!?
我的bot怎麼下線了???
要怎麼解決這個問題?
很簡單!
打開就好了
ㄟˊ奇怪他怎麼不讓我開
年輕人~
發揮你的鈔能力吧!!!
這樣我就不用備課了🥳
uptime robot!
-
免費
-
自動網站監測
-
發送訊息提醒
uptime robot!
#新建一個檔案 keep_alive.py
#不要問我這在幹嘛
from flask import Flask
from threading import Thread
app = Flask('')
@app.route('/')
def main():
return 'Bot is aLive!'
def run():
app.run(host="0.0.0.0", port=8080)
def keep_alive():
server = Thread(target=run)
server.start()
uptime robot!
#在main.py最前面加上
import keep_alive
#在bot.run前一行加上
keep_alive.keep_alive()
#然後跑跑看?
uptime robot!
複製網址
uptime robot!
貼上網址
搞定!
Slash Command
Slash Command是什麼
反正就長這樣
我也不會解釋
Slash Command
#寫在cmd.py
from discord import app_commands
import discord #導入 Discord.py
from discord.ext import commands
from core.classes import Cog_Extension #從你的classes.py 引入 class
class Cmd(Cog_Extension):
@commands.command() #同步指令樹的指令
async def sync(self, ctx):
fmt = await ctx.bot.tree.sync()
await ctx.send(f'Synced {len(fmt)} commands')
@app_commands.command(name="slash", description="test command")
async def slash(self, interaction: discord.Interaction):
await interaction.response.send_message("Hello Slash!")
關於slash command
有興趣可以看一下
對我懶得做簡報
反正也沒人來聽課QAQ
Converter
本來沒有要教這個
但我覺得今天的課好像有點水
Basic Converter
@bot.command()
async def add(ctx, a: int, b: int):
# ^ 這個東西就是converter
await ctx.send(a + b)
自己寫一個?
def to_upper(argument):
return argument.upper()
@bot.command()
async def up(ctx, *, content: to_upper):
await ctx.send(content)
Advanced Converter
import random
class Slapper(commands.Converter):
async def convert(self, ctx, argument):
to_slap = random.choice(ctx.guild.members)
return f'{ctx.author} slapped {to_slap} because *{argument}*'
@bot.command()
async def slap(ctx, *, reason: Slapper):
await ctx.send(reason)
如果需要用到ctx?
Special Converter
import typing
@bot.command()
async def union(ctx, what: typing.Union[discord.TextChannel, discord.Member]):
#如果符合discord.Textchannel就使用這個converter
#如果不符合,就試試看discord.Member
#由左至右檢查,都不符合會出現錯誤
#裡面可以放任何你要的converter
await ctx.send(what)
typing.Union
Special Converter
import typing
@bot.command()
async def bottles(ctx, amount: typing.Optional[int] = 99, *, liquid="beer"):
#如果傳入的第一個參數不是int,
#則amount=99(如果不指定值則為None),並把第一個參數傳遞給liquid(跳過amount)
await ctx.send(f'{amount} bottles of {liquid} on the wall!')
typing.Optional
Special Converter
from typing import Literal
@bot.command()
async def shop(ctx, buy_sell: Literal['buy', 'sell'], amount: Literal[1, 2], *, item: str):
await ctx.send(f'{buy_sell.capitalize()}ing {amount} {item}(s)!')
#傳入值要符合buy或sell其中一個,不然會出錯
#同理,第二個值如果不是1或2就會出錯
Literal
Special Converter
@bot.command()
async def slap(ctx, members: commands.Greedy[discord.Member], *, reason='no reason'):
slapped = ", ".join(x.name for x in members)
await ctx.send(f'{slapped} just got slapped for {reason}')
#一直測試參數是否為discord.Member,直到不符合才會跳下一個參數
Greedy
Converter
THE END
希望這次可以準時?
Discord Bot-2
By times1-chang
Discord Bot-2
- 177