Discord Botで予め準備しておいた音楽を連続再生する
Top→Discord Botの作り方 - 1/(1+e^(-ax))
prev→Discord Botで予め準備しておいた音楽を再生する - 1/(1+e^(-ax))
next→Discord BotでCogを使ってみる - 1/(1+e^(-ax))
前回作成したbgmコマンドを、!bgmと入力した回数だけ再生されるようにしてみます。
作成にあたりこちらの記事を参考にしました。→Pythonで始める録音機能付きDiscord Bot: (4) 音楽ファイルを再生する - Qiita
前回vc.play(...)で音楽ファイルを再生しましたが、これをvc.play(... , after= function)とすることで再生終了時に関数functionを呼び出すことができるのでこれを利用します。
また、今回は特定の1曲だけを再生しますが、後々のことを考えて再生にはキューを使用することにします。
キューという概念の説明については割愛します。そこまで難しいものではないので軽く調べてもらえば理解できると思います。
pythonのasyncioというライブラリにキューが実装されてるので、これを都合よく改造します。
再生キューであるAudioQueueクラス
class AudioQueue(asyncio.Queue): def __init__(self): super().__init__(0) #再生キューの上限を設定しない def __getitem__(self, idx): return self._queue[idx] #idx番目を取り出し def to_list(self): return list(self._queue) #キューをリスト化 def reset(self): self._queue.clear() #キューのリセット
asyncio.Queueクラスを継承しています。
クラスがよく分からない方は、とりあえずこれで再生キューが作成できたと思ってもらって結構です。
次に、現在の再生状況を管理するAudioStatusクラスを作成します。
これには、自分が今どのボイスチャンネルにいて、再生キューがどうなっているのかといった情報を保持してもらいます。
class AudioStatus: def __init__(self, vc): self.vc = vc #自分が今入っているvc self.queue = AudioQueue() #再生キュー self.playing = asyncio.Event() asyncio.create_task(self.playing_task()) #曲の追加 async def add_audio(self, path): await self.queue.put(path) #曲の再生(再生にはffmpegが必要) async def playing_task(self): while True: self.playing.clear() try: path = await asyncio.wait_for(self.queue.get(), timeout = 100) except asyncio.TimeoutError: asyncio.create_task(self.leave()) selfpath = os.path.dirname(__file__) self.vc.play(discord.FFmpegPCMAudio(executable=selfpath+"/bin/ffmpeg.exe", source=path), after = self.play_next) await self.playing.wait() #playing_taskの中で呼び出される #再生が終わると次の曲を再生する def play_next(self, err=None): self.bgminfo = None self.playing.set() return #vcから切断 async def leave(self): self.queue.reset() #キューのリセット if self.vc: await self.vc.disconnect() self.vc = None return
前回グローバル変数VCで行っていたボイスチャンネルの管理もこのクラスで行うので、切断用の関数をこちらに実装します。
AudioStatusはadd_audioでキューに曲を追加することができるので、プログラムの完成版は次のようになります。
import asyncioやawaitの抜けに注意しましょう。
import discord from discord.ext import commands import os import asyncio TOKEN = "token" #トークン PREFIX = '!' #prefix=接頭辞 #bgmコマンドで使う再生キュー class AudioQueue(asyncio.Queue): def __init__(self): super().__init__(0) #再生キューの上限を設定しない def __getitem__(self, idx): return self._queue[idx] #idx番目を取り出し def to_list(self): return list(self._queue) #キューをリスト化 def reset(self): self._queue.clear() #キューのリセット #bgmコマンドで使う,現在の再生状況を管理するクラス class AudioStatus: def __init__(self, vc): self.vc = vc #自分が今入っているvc self.queue = AudioQueue() #再生キュー self.playing = asyncio.Event() asyncio.create_task(self.playing_task()) #曲の追加 async def add_audio(self, path): await self.queue.put(path) #曲の再生(再生にはffmpegが必要) async def playing_task(self): while True: self.playing.clear() try: path = await asyncio.wait_for(self.queue.get(), timeout = 100) except asyncio.TimeoutError: asyncio.create_task(self.leave()) selfpath = os.path.dirname(__file__) self.vc.play(discord.FFmpegPCMAudio(executable=selfpath+"/bin/ffmpeg.exe", source=path), after = self.play_next) await self.playing.wait() #playing_taskの中で呼び出される #再生が終わると次の曲を再生する def play_next(self, err=None): self.bgminfo = None self.playing.set() return #vcから切断 async def leave(self): self.queue.reset() #キューのリセット if self.vc: await self.vc.disconnect() self.vc = None return #botの作成 bot = commands.Bot(command_prefix=PREFIX) Audio_queue = None #AudioStatusの宣言 #予め決めておいた音楽ファイルを再生する @bot.command() async def bgm(ctx): """play music""" global Audio_queue #この関数内ではVCはグローバル変数のVCを指す if (ctx.author.voice is None): #送信者がボイスチャンネルにいなければエラーを返す await send_message(ctx.send, ctx.author.mention, 'ボイスチャンネルが見つかりません') return if ((Audio_queue is None) or (Audio_queue.vc is None)): #botがボイスチャンネルに入っていなければ voice_channel = ctx.author.voice.channel.id #送信者の入っているボイスチャンネルのID vc = await bot.get_channel(voice_channel).connect() #ボイスチャンネルに入る Audio_queue = AudioStatus(vc) path = os.path.dirname(__file__) #このファイルが置いてあるディレクトリまでのファイルパス #music.mp3をキューに追加 await Audio_queue.add_audio(path+'/bgm/music.mp3') return #botをボイスチャンネルから切断する @bot.command() async def remove(ctx): await Audio_queue.leave() return bot.run(TOKEN)
!bgmと2回打つとmusic.mp3が2回再生されるようになれば成功です。
お疲れ様でした。