Discord BotでCogを使ってみる
Top→Discord Botの作り方 - 1/(1+e^(-ax))
prev→Discord Botで予め準備しておいた音楽を連続再生する - 1/(1+e^(-ax))
next→特定のフォルダにあるファイルの一覧を作成する - 1/(1+e^(-ax))
前回で連続再生が可能になったので今回は曲の指定…といきたいところなのですが、曲の一覧をグローバル変数に保存しておいたり毎回読み込むのもアレなのでCogというものを活用してみたいと思います。
Cogとは
Discord botでhelpコマンドを使ったことがある人は、コマンドをグループ分けしているものだと思ってもらえばいいと思います。
これのBGM管理にあたるグループですね。
プログラムで言うとクラスのようなものになります(実際クラスで宣言してますし)。
主な違いとしては、第一引数にselfが入ることと、
@bot.command()→@commands.command()となることです。
下に、前回のプログラムをCogを使って書き直したものを置いておきます。
ついでにAudio_queueもインスタンス変数(self.audio_status)として書き直しています。
最後のbot.add_cog()で作成したcogをbotに付与しています。
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) class __BGM(commands.Cog, name= 'BGM'): #BGMという名前でCogを定義する #初期化 def __init__(self, bot): super().__init__() self.bot = bot self.audio_status = None self.path = os.path.dirname(__file__) #このファイルが置いてあるディレクトリまでのファイルパス #予め決めておいた音楽ファイルを再生する @commands.command() async def bgm(self, ctx): """play music""" global Audio_queue #この関数内ではVCはグローバル変数のVCを指す if (ctx.author.voice is None): #送信者がボイスチャンネルにいなければエラーを返す await send_message(ctx.send, ctx.author.mention, 'ボイスチャンネルが見つかりません') return if ((self.audio_status is None) or (self.audio_status.vc is None)): #botがボイスチャンネルに入っていなければ voice_channel = ctx.author.voice.channel.id #送信者の入っているボイスチャンネルのID vc = await bot.get_channel(voice_channel).connect() #ボイスチャンネルに入る self.audio_status = AudioStatus(vc) #music.mp3をキューに追加 await self.audio_status.add_audio(self.path+'/bgm/music.mp3') return #botをボイスチャンネルから切断する @commands.command() async def remove(self, ctx): await self.audio_status.leave() return bot.add_cog(__BGM(bot=bot)) bot.run(TOKEN)
挙動は前回と全く同じはずです。
次回は、ファイル名を指定して再生する方法を考えます。
短いですが今回はここまでです。お疲れ様でした。