discord允許我們提供音檔來讓機器人播放聲音
如果音檔為音樂,則可以實現播放音樂的功能
環境準備
播放音樂以及抓取音檔需要額外的套件,請一樣依照自己的電腦環境來替換開頭:
1
| pip install yt-dlp discord.py[voice] python-ffmpeg
|
yt-dlp
是提取Youtube影片資料的
discord.py[voice]
是discord.py的語音擴充
python-ffmpeg
可以把音檔轉換成二進制檔案供Discord使用
屬性介紹
voice屬性
之前我們講過使用者有許多屬性,其中voice
沒有提到,今天簡單介紹我們需要用到的部分
user.voice
屬性本身屬於discord.VoiceState
類別,代表目前該使用者的語音狀態,如果沒有在語音狀態則是None
如果存在的話會有以下常用屬性(非全部)
deaf
: 是否拒聽
mute
: 是否靜音
channel
: 連線到的頻道
self_stream
: 是不是正在直播
我們今天會需要他的channel
屬性
voice_clients
這個屬性是bot
所有的語音連線狀態
與使用者不同,一個機器人可以同時在不同伺服器連線到語音頻道(不過一個伺服器一樣限制一個頻道)
bot.voice_clients
列出了所有機器人連線到的語音用戶端(可以想成一個專屬語音的虛擬使用者),屬於discord.VoiceClient
類別
有channel
跟guild
(頻道/伺服器)屬性可以給我們取用,還能進行其他播放的操作
discord.utils.get()
這是一個特殊的函數,是discord提供的方便函數
其用法為
1
| result = discord.utils.get(一個列表, 屬性=值)
|
意思是在一個列表裡面一一尋找,直到找到某一個項目的屬性符合值,舉例來說
1
| result = discord.utils.get(社團列表, name="電算社")
|
這時候result就會找到一個物件,其name
屬性為"電算社"
的並返回給result
這時候我們就可以拿result
來用
但如果沒有找到的話result
會是None
如果搭配voice_clients
就可以尋找機器人所有語音用戶端內,是當前這個伺服器的那個項目
加入與退出
加入
我們將請使用者先加入一個語音頻道,然後使機器人也加入該頻道
這時候就需要考慮到使用者如果還沒進去一個頻道,就要請他進去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @bot.tree.command() async def join(interaction: discord.Interaction):
v = interaction.user.voice vc = discord.utils.get(bot.voice_clients, guild=interaction.guild)
if v and not vc:
await v.channel.connect() await interaction.response.send_message(f"已經連線至 {v.channel.mention}") elif not v: await interaction.response.send_message("請先加入一個語音頻道") else: await interaction.response.send_message(f"機器人已經連線了")
|
退出
退出時一樣要考慮機器人是不是真的在一個頻道內
1 2 3 4 5 6 7 8 9 10
| @bot.tree.command(description="讓機器人離開語音頻道") async def leave(interaction: discord.Interaction): vc = discord.utils.get(bot.voice_clients, guild=interaction.guild) if vc: await vc.disconnect(force=True) await interaction.response.send_message("已經離線") else: await interaction.response.send_message("機器人不在語音頻道內")
|
播放本地音訊
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @bot.tree.command(description="播放音訊") async def play(interaction: discord.Interaction, name: str): await interaction.response.defer() vc = discord.utils.get(bot.voice_clients, guild=interaction.guild) if not vc: await interaction.response.send_message("機器人不在語音頻道內") return
audio = discord.FFmpegPCMAudio(f"./{name}")
vc.play(audio) await interaction.followup.send(f"正在播放 {name}")
|
暫停、繼續和停止
暫停
這裡還需要多考慮一件事:機器人有沒有在播音樂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @bot.tree.command(name="pause", description="暫停播放音樂") async def pause(interaction: discord.Interaction):
vc: discord.VoiceClient = discord.utils.get(bot.voice_clients, guild=interaction.guild) if not vc: await interaction.response.send_message("機器人不在語音頻道內") return
if vc.is_playing(): vc.pause() await interaction.response.send_message("音樂已暫停") else: await interaction.response.send_message("目前沒有音樂在播放")
|
繼續
同理,繼續之前需要檢查機器人是不是暫停狀態
1 2 3 4 5 6 7 8 9 10 11 12
| @bot.tree.command(name="resume", description="繼續播放音樂") async def resume(interaction: discord.Interaction): vc: discord.VoiceClient = discord.utils.get(bot.voice_clients, guild=interaction.guild) if not vc: await interaction.response.send_message("機器人不在語音頻道內") return
if vc.is_paused(): vc.resume() await interaction.response.send_message("音樂已繼續播放") else: await interaction.response.send_message("音樂未被暫停")
|
停止
1 2 3 4 5 6 7 8 9 10 11 12
| @bot.tree.command(name="stop", description="停止播放音樂") async def stop(interaction: discord.Interaction): vc: discord.VoiceClient = discord.utils.get(bot.voice_clients, guild=interaction.guild) if not vc: await interaction.response.send_message("機器人不在語音頻道內") return
if vc.is_playing(): vc.stop() await interaction.response.send_message("已經停止") else: await interaction.response.send_message("沒有在播音樂")
|