[PYTHON] Introduction to discord.py (3) Using voice

Introduction

I run an unofficial server for discord.py (although some developers). Questions are also accepted here. You can also create a personal channel and get support there for ** people who want long-term support **. If you would like to receive personal support, please enter from the invitation url below and DM to @ Sumidora # 8931. https://discord.gg/KPp2Wsu ** Please also ask questions about this article here **

About this article

This article is a step-by-step study of discord.py. First you will learn the basic writing method, and then you will learn the advanced content. 【series】

Introduction to discord.py (1) Introduction to discord.py (2) Introduction to discord.py (3)

Caution

** This article is for people who can do even a little Python. ** ** However, you can use it just by copying it, but you will not be able to write it after that, so if you want to create more individual functions, It is recommended to study using books, paiza learning, dot installation, Progate, Kyoto University textbook. I will. The book I recommend is Shingo Tsuji's [Python Startbook](https://www.amazon.co.jp/Python Startbook-Augmented Revised Edition-Tsuji-Shingo / dp / 4774196436 /).

The operating environment of the author

Python 3.8.3 Mac OS Catalina 10.15.5 discord.py-1.4.1

About this article

In this article, it will be an article that will follow the usage in order, not the system like each introduction so far.

Install discord.py with audio

Until now, you installed pip install discord.py, but this doesn't install the library for audio. Therefore, you need to install the library for audio as well.

pip install discord.py[voice]

Finally, write [voice] to install the voice library as well.

If you have already installed it, uninstall it first with pip uninstall discord.py.

Connect to audio

First, let's write the code that connects to the voice.

This time, we will create a function to connect by hitting ! Join and disconnect by hitting! Leave.

Determine if the sender of the message is connected to a voice channel

If the sender of the message is not connected to a voice channel, you will not know which voice channel to connect to.

So, first we need to determine if the sender of the message is connected to the voice channel.

Here we use the discord.Member.voice variable. This variable returns a discord.VoiceState instance if it was connected to a voice channel, and None if it wasn't.

# in on_message

if message.content == "!join":
    if message.author.voice is None:
        await message.channel.send("You are not connected to a voice channel.")
        return
    ...

Connect to voice channel

After judging in the above section, the next step is to connect to the voice channel. You can connect with the discord.VoiceChannel.connect coroutine function, but first you need to get an instance of discord.VoiceChannel.

You can also get this with the discord.Client.get_channel function, but you can use the discord.VoiceState.channel variable as it is also a VoiceChannel instance.

# in on_message

if message.content == "!join":
    if message.author.voice is None:
        await message.channel.send("You are not connected to a voice channel.")
        return
    #Connect to voice channel
    await message.author.voice.channel.connect()

    await message.channel.send("Connected.")

Now you can connect to your voice channel!

Disconnect from voice channel

Next, disconnect from the voice channel. This requires a slightly special method.

First, in order to disconnect from the voice channel, you need to execute the discord.VoiceClient.disconnect coroutine function, but you need to get this discord.VoiceClient instance from discord.Guild.

voice_client = message.guild.voice_client

This value will be discord.VoiceClient if connected, None if not connected.

With this,


import discord


client = discord.Client()


@client.event
async def on_message(message: discord.Message):
    #Ignore if the sender of the message is a bot
    if message.author.bot:
        return

    if message.content == "!join":
        if message.author.voice is None:
            await message.channel.send("You are not connected to a voice channel.")
            return
        #Connect to voice channel
        await message.author.voice.channel.connect()
        await message.channel.send("Connected.")

    elif message.content == "!leave":
        if message.guild.voice_client is None:
            await message.channel.send("Not connected.")
            return

        #Disconnect
        await message.guild.voice_client.disconnect()

        await message.channel.send("I disconnected.")

You can write like this.

Move voice channel

Use the discord.VoiceClient.move_to coroutine function. Pass an instance of a new audio channel to move_to.

#Go to the voice channel where the user who sent the message is
message.guild.voice_client.move_to(message.author.voice.channel)

Play / pause audio

After connecting to the voice channel, let's play the voice. Here we assume that you have a file called ʻexample.mp3`.

You will also need something called ffmpeg, so please include it (search for it and you will find many ways to enter it).

Try to play it by typing ! play.

Play audio


if message.content == "!play":
    if message.guild.voice_client is None:
        await message.channel.send("Not connected.")
        return
    message.guild.voice_client.play(discord.FFmpegPCMAudio("example.mp3"))

You can play with just this! Surprisingly, the play function is not a coroutine function.

Stop the voice

You can pause with the discord.VoiceClient.pause function.

You can also stop (cannot resume) with the discord.VoiceClient.stop function.

Resume audio playback

You can resume playback with the discord.VoiceClient.resume function.

Change the volume of audio

You can change it by using discord.PCMVolumeTransformer.

source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio("example.mp3"), volume=0.5)

message.guild.voice_client.play(source)

You can specify the volume for volume. The original volume is 1 and the lowest is 0. (Half at 0.5)

Play Youtube music

Caution

** The content from here onwards may conflict with Youtube's TOS, so please do so at your own risk. Only an example is shown here. ** **

You can refer to here, but this content is advanced (difficult to write by yourself), so it's easy. I will introduce what I did.

First, run pip install youtube_dl in the shell to install the youtube_dl library.

Then write this at the beginning of the file:


import asyncio

import discord
import youtube_dl
# Suppress noise about console usage from errors
youtube_dl.utils.bug_reports_message = lambda: ''

ytdl_format_options = {
    'format': 'bestaudio/best',
    'outtmpl': '%(extractor)s-%(id)s-%(title)s.%(ext)s',
    'restrictfilenames': True,
    'noplaylist': True,
    'nocheckcertificate': True,
    'ignoreerrors': False,
    'logtostderr': False,
    'quiet': True,
    'no_warnings': True,
    'default_search': 'auto',
    'source_address': '0.0.0.0' # bind to ipv4 since ipv6 addresses cause issues sometimes
}

ffmpeg_options = {
    'options': '-vn'
}

ytdl = youtube_dl.YoutubeDL(ytdl_format_options)


class YTDLSource(discord.PCMVolumeTransformer):
    def __init__(self, source, *, data, volume=0.5):
        super().__init__(source, volume)

        self.data = data

        self.title = data.get('title')
        self.url = data.get('url')

    @classmethod
    async def from_url(cls, url, *, loop=None, stream=False):
        loop = loop or asyncio.get_event_loop()
        data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=not stream))

        if 'entries' in data:
            # take first item from a playlist
            data = data['entries'][0]

        filename = data['url'] if stream else ytdl.prepare_filename(data)
        return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data)

This is located at https://github.com/Rapptz/discord.py/blob/master/examples/basic_voice.py.

Then use it to make youtube music playable.


import asyncio

import discord
import youtube_dl
# Suppress noise about console usage from errors
youtube_dl.utils.bug_reports_message = lambda: ''

ytdl_format_options = {
    'format': 'bestaudio/best',
    'outtmpl': '%(extractor)s-%(id)s-%(title)s.%(ext)s',
    'restrictfilenames': True,
    'noplaylist': True,
    'nocheckcertificate': True,
    'ignoreerrors': False,
    'logtostderr': False,
    'quiet': True,
    'no_warnings': True,
    'default_search': 'auto',
    'source_address': '0.0.0.0' # bind to ipv4 since ipv6 addresses cause issues sometimes
}

ffmpeg_options = {
    'options': '-vn'
}

ytdl = youtube_dl.YoutubeDL(ytdl_format_options)


class YTDLSource(discord.PCMVolumeTransformer):
    def __init__(self, source, *, data, volume=0.5):
        super().__init__(source, volume)

        self.data = data

        self.title = data.get('title')
        self.url = data.get('url')

    @classmethod
    async def from_url(cls, url, *, loop=None, stream=False):
        loop = loop or asyncio.get_event_loop()
        data = await loop.run_in_executor(None, lambda: ytdl.extract_info(url, download=not stream))

        if 'entries' in data:
            # take first item from a playlist
            data = data['entries'][0]

        filename = data['url'] if stream else ytdl.prepare_filename(data)
        return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data)


client = discord.Client()


@client.event
async def on_message(message: discord.Message):
    #Ignore if the sender of the message is a bot
    if message.author.bot:
        return

    if message.content == "!join":
        if message.author.voice is None:
            await message.channel.send("You are not connected to a voice channel.")
            return
        #Connect to voice channel
        await message.author.voice.channel.connect()
        await message.channel.send("Connected.")

    elif message.content == "!leave":
        if message.guild.voice_client is None:
            await message.channel.send("Not connected.")
            return

        #Disconnect
        await message.guild.voice_client.disconnect()

        await message.channel.send("I disconnected.")
    elif message.content.startswith("!play "):
        if message.guild.voice_client is None:
            await message.channel.send("Not connected.")
            return
        #Do not play if playing
        if message.guild.voice_client.is_playing():
            await message.channel.send("Playing.")
            return

        url = message.content[6:]
        #Download music from youtube
        player = await YTDLSource.from_url(url, loop=client.loop)

        #Reproduce
        await message.guild.voice_client.play(player)

        await message.channel.send('{}To play.'.format(player.title))

    elif message.content == "!stop":
        if message.guild.voice_client is None:
            await message.channel.send("Not connected.")
            return

        #Do not run if not playing
        if not message.guild.voice_client.is_playing():
            await message.channel.send("Not playing.")
            return

        message.guild.voice_client.stop()

        await message.channel.send("It has stopped.")

At the end

How was that. I explained how to use voice. If you have any other points you would like us to explain, please leave them in the comments or on the server.

In the next article, I hope I can explain the commands framework.

Well then.

Recommended Posts

Introduction to discord.py (3) Using voice
Introduction to discord.py (2)
Introduction to discord.py
Introduction to MQTT (Introduction)
Introduction to Scrapy (1)
Introduction to Scrapy (3)
Introduction to Supervisor
Introduction to Tkinter 1: Introduction
Introduction to Discrete Event Simulation Using Python # 1
[PyTorch] Introduction to document classification using BERT
Introduction to PyQt
Introduction to Scrapy (2)
[Linux] Introduction to Linux
Introduction to discord.py (1st day) -Preparation for discord.py-
Introduction to Scrapy (4)
Introduction to Discrete Event Simulation Using Python # 2
Introduction to Tornado (3): Development using templates [Practice]
[PyTorch] Introduction to Japanese document classification using BERT
Convert voice to text using Azure Speech SDK
Introduction to Tornado (2): Introduction to development using templates-Dynamic page generation-
An introduction to voice analysis for music apps
Introduction to Scapy ② (ICMP, HTTP (TCP) transmission using Scapy)
Introduction to Web Scraping
Introduction to Nonparametric Bayes
Introduction to Python language
Introduction to TensorFlow-Image Recognition
Introduction to OpenCV (python)-(2)
Introduction to Dependency Injection
Introduction to Private Chainer
Introduction to machine learning
[Introduction to Python] How to stop the loop using break?
[Introduction to cx_Oracle] (Part 13) Connection using connection pool (client side)
[Introduction to Python] How to write repetitive statements using for statements
[Technical book] Introduction to data analysis using Python -1 Chapter Introduction-
AOJ Introduction to Programming Topic # 1, Topic # 2, Topic # 3, Topic # 4
Easy introduction to home hack with Raspberry Pi and discord.py
Introduction to electronic paper modules
A quick introduction to pytest-mock
Introduction to dictionary lookup algorithm
[Learning memorandum] Introduction to vim
Introduction to PyTorch (1) Automatic differentiation
opencv-python Introduction to image processing
[Introduction to Python] How to write conditional branches using if statements
Introduction to Python Django (2) Win
Kubernetes Scheduler Introduction to Homebrew
An introduction to machine learning
[Introduction to cx_Oracle] Overview of cx_Oracle
Day 67 [Introduction to Kaggle] Have you tried using Random Forest?
[Introduction to pytorch-lightning] First Lit ♬
Introduction to Anomaly Detection 1 Basics
Post to Twitter using Python
[Introduction to Systre] Fibonacci Retracement ♬
Start to Selenium using python
Introduction to Nonlinear Optimization (I)
AOJ Introduction to Programming Topic # 5, Topic # 6
Introduction to Bayesian Modeling Using pymc3 Bayesian-Modeling-in-Python Japanese Translation (Chapter 0-2)
Introduction of caffe using pyenv
Introduction to Deep Learning ~ Learning Rules ~
[Introduction to Python] <list> [edit: 2020/02/22]
Introduction to Python (Python version APG4b)
An introduction to Python Programming