---
tags: report
---
> 建議從網站看: h<!---->ttps://hackmd.io/@konchin/2021finalreport
# 進階程式設計期末專題 - Discord Bot
## 動機
因為在家遠距學習很閒,而且那時候messenger越改越爛,我覺得群組換到discord會比較好
但因為discord自訂貼圖的上限偏小,而且沒付錢不能用,所以就想自己寫一個有這功能的bot
## 目標
* 在聊天頻道傳出特定訊息時,上傳圖片
* 用指令管理身分組
* 在身分組頻道點選表情符號加入身分組
* 伺服器加入審核
* 實用指令集
## 實作
### 概念
用 `discord.py` 這個discord官方提供的函式庫實作
用 `json` 格式來儲存所需的資料
### 示意圖

### code
上傳圖片的程式碼如下
```python=!
@commands.Cog.listener()
async def on_message(self, msg):
if msg.author == self.bot.user:
return
with open("./jsons/roles.json",'r',encoding='utf8') as jfile:
jrole = json.load(jfile)
if msg.author.id in jrole["banned"]:
return
with open("./jsons/pictures_v2.json", 'r', encoding="utf8") as jfile:
jdata = json.load(jfile)
msg_fixed = msg.content.replace(' ', '').lower()
msg_fixed = msg_fixed.replace(' ', '')
if msg_fixed in jdata["keys"]:
async with msg.channel.typing():
image = discord.File(f"./pictures/{choice(jdata['keys'][msg_fixed])}")
await msg.channel.send(file=image)
```
`json` 文本示意如下
```json=!
{
"keys": {
"gay": [
"160.jpg"
]
},
"pictures": {
"160.jpg": [
"gay"
]
}
```
加入圖片程式碼如下
```python=!
@picture.command(aliases=['u'])
async def upload(self, ctx, url: str= ''):
if not is_permitted(ctx.author):
await ctx.send("Command denied. Out of permission.", delete_after=3)
return
if not len(ctx.message.attachments) and not len(url):
await ctx.send("No attachments or url.", delete_after=3)
return
with open("./jsons/pictures_v2.json", 'r', encoding="utf8") as jfile:
jdata = json.load(jfile)
with open("./jsons/setting.json", 'r', encoding="utf8") as jfile:
jsdata = json.load(jfile)
path = "./pictures/"
for attachment in ctx.message.attachments:
filename = f"{jsdata['Picture_count']}.{attachment.filename.split('.')[-1].lower()}"
jdata['pictures'][filename] = []
jsdata['Picture_count'] += 1
await attachment.save(path + filename)
await ctx.send(f"{filename} saved.")
with open("./jsons/pictures_v2.json", "w", encoding="utf8") as jfile:
json.dump(jdata, jfile, indent=4)
with open("./jsons/setting.json", 'w', encoding="utf8") as jfile:
json.dump(jsdata, jfile, indent=4)
if url == '':
return
if not get(url):
await ctx.send("Url error, please check your url.")
return
res = get(url, stream=True)
if res.status_code != 200:
await ctx.send("Upload failed, please check your url.", delete_after=3)
return
res.raw.decode_content = True
filename = f"{jsdata['Picture_count']}.{url.split('.')[-1].lower()}"
with open(path + filename, 'wb') as file:
shutil.copyfileobj(res.raw, file)
jdata['pictures'][filename] = []
jsdata['Picture_count'] += 1
await ctx.send(f"{filename} saved.")
with open("./jsons/pictures_v2.json", "w", encoding="utf8") as jfile:
json.dump(jdata, jfile, indent=4)
with open("./jsons/setting.json", 'w', encoding="utf8") as jfile:
json.dump(jsdata, jfile, indent=4)
@picture.command(aliases=['b'])
async def bond(self, ctx, key, file):
if not is_permitted(ctx.author):
await ctx.send("Command denied. Out of permission.", delete_after=3)
return
with open("./jsons/pictures_v2.json", 'r', encoding="utf8") as jfile:
jdata = json.load(jfile)
if file not in jdata["pictures"]:
await ctx.send("File not exist.")
return
if key not in jdata["keys"]:
jdata["keys"][key] = []
jdata["keys"][key].append(file)
jdata["pictures"][file].append(key)
with open("./jsons/pictures_v2.json", "w", encoding="utf8") as jfile:
json.dump(jdata, jfile, indent=4)
await ctx.send(f"{file} has bonded to {key}.")
channel = ctx.guild.get_channel(jsdata["Picture_list_ch"])
async with channel.typing():
image = discord.File(f"./pictures/{file}")
await channel.send(f"**alias:** {key}",file=image)
```
### 實際使用情況
**1.**
同學傳了一張圖,我想對這張圖表達我的想法
在聊天頻道打`gay`,discord bot就會隨機上傳一張`gay`這個標籤相應的圖

**2.**
在同一個訊息中,文字打`$picture upload`(或是簡寫`$p u`),同時上傳圖片,discord bot 的伺服器端就會下載那張照片(或動圖、影片)
接下來透過`$picture bond`(簡寫`$p b`)將伺服器端圖片編號和標籤進行綁定
(同一張圖片可以綁定多個標籤,反之亦然,同個標籤也可以綁定多張圖片)
之後就可以在discord bot運行的頻道使用

如下圖

## 運行平台
- Raspberry pi 4 (4GB RAM)
- SanDisk Extreme PRO microSDXC UHS-I Card (128GB)
- Raspberry pi OS
## 外部連結
[Discord bot - Shiki Natsume 完整使用說明](/@konchin/discord_bot_commands)
## 參考資料
[discord.py API Reference](https://discordpy.readthedocs.io/en/stable/api.html)
[Youtube playlist: Proladon - Code a discord bot](https://youtube.com/playlist?list=PLSCgthA1Anif1w6mKM3O6xlBGGypXtrtN)