1/(1+e^(-ax))

ポケモンとかPCとか

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コマンドを使ったことがある人は、コマンドをグループ分けしているものだと思ってもらえばいいと思います。
f:id:Sigmoid_poke:20210305175321p:plain


これの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)


挙動は前回と全く同じはずです。
次回は、ファイル名を指定して再生する方法を考えます。
短いですが今回はここまでです。お疲れ様でした。


next→特定のフォルダにあるファイルの一覧を作成する - 1/(1+e^(-ax))