--- tags: report --- > 建議從網站看: h<!---->ttps://hackmd.io/@konchin/2021finalreport # 進階程式設計期末專題 - Discord Bot ## 動機 因為在家遠距學習很閒,而且那時候messenger越改越爛,我覺得群組換到discord會比較好 但因為discord自訂貼圖的上限偏小,而且沒付錢不能用,所以就想自己寫一個有這功能的bot ## 目標 * 在聊天頻道傳出特定訊息時,上傳圖片 * 用指令管理身分組 * 在身分組頻道點選表情符號加入身分組 * 伺服器加入審核 * 實用指令集 ## 實作 ### 概念 用 `discord.py` 這個discord官方提供的函式庫實作 用 `json` 格式來儲存所需的資料 ### 示意圖 ![](https://i.imgur.com/mydYeq3.png) ### 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`這個標籤相應的圖 ![](https://i.imgur.com/lkKMMaX.png =500x) **2.** 在同一個訊息中,文字打`$picture upload`(或是簡寫`$p u`),同時上傳圖片,discord bot 的伺服器端就會下載那張照片(或動圖、影片) 接下來透過`$picture bond`(簡寫`$p b`)將伺服器端圖片編號和標籤進行綁定 (同一張圖片可以綁定多個標籤,反之亦然,同個標籤也可以綁定多張圖片) 之後就可以在discord bot運行的頻道使用 ![](https://i.imgur.com/fYHqDGr.png =500x) 如下圖 ![](https://i.imgur.com/NidKkgc.png =500x) ## 運行平台 - 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)