[PYTHON] [Latest version] Play YouTube videos on discord.py!

At first

I'm writing an article in MarkDown for the first time, so I think there are various strange parts, but I hope you can see it with warm eyes (; ´Д `) Please let me know if you have any corrections ... And since discord.py is also a beginner, I hope you can see it with warm eyes, but if you make a mistake, please let me know if you find it.

Operating environment

Python 3.9.1 Discord.py 1.5.1 PyNaCl 1.4.0 youtube_dl 2020.12.26 Windows10

Preparation-Package

First of all, it is necessary to prepare the necessary packages, but it is a prerequisite that ** the environment for running Bot is ready **. So Python and Discord.py are probably included, so I'll omit them. I want to use youtube_dl this time

python


$ pip install youtube_dl

Let's run youtube_dl in the terminal.

Preparation -ffmpeg

First, go to Site, and I think there are two git Links in the middle. Either one is fine, so download it (click the URL to start the download).

After downloading, unzip it and it will contain various items.

Downloaded ffmpeg file



bin
┗ ffmpeg.exe

Since it should be, copy or cut ffmpeg.exe and ** Paste it into the directory that contains the bot's main files **.

Now that you're ready, here's the code.

code

import asyncio

import discord
import youtube_dl

from discord.ext import commands

# 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)


class Music(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    @commands.command()
    async def join(self, ctx, *, channel: discord.VoiceChannel):
        """Joins a voice channel"""

        if ctx.voice_client is not None:
            return await ctx.voice_client.move_to(channel)

        await channel.connect()

    @commands.command()
    async def play(self, ctx, *, query):
        """Plays a file from the local filesystem"""

        source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio(query))
        ctx.voice_client.play(source, after=lambda e: print('Player error: %s' % e) if e else None)

        await ctx.send('Now playing: {}'.format(query))

    @commands.command()
    async def yt(self, ctx, *, url):
        """Plays from a url (almost anything youtube_dl supports)"""

        async with ctx.typing():
            player = await YTDLSource.from_url(url, loop=self.bot.loop)
            ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None)

        await ctx.send('Now playing: {}'.format(player.title))

    @commands.command()
    async def stream(self, ctx, *, url):
        """Streams from a url (same as yt, but doesn't predownload)"""

        async with ctx.typing():
            player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=True)
            ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None)

        await ctx.send('Now playing: {}'.format(player.title))

    @commands.command()
    async def volume(self, ctx, volume: int):
        """Changes the player's volume"""

        if ctx.voice_client is None:
            return await ctx.send("Not connected to a voice channel.")

        ctx.voice_client.source.volume = volume / 100
        await ctx.send("Changed volume to {}%".format(volume))

    @commands.command()
    async def stop(self, ctx):
        """Stops and disconnects the bot from voice"""

        await ctx.voice_client.disconnect()

    @play.before_invoke
    @yt.before_invoke
    @stream.before_invoke
    async def ensure_voice(self, ctx):
        if ctx.voice_client is None:
            if ctx.author.voice:
                await ctx.author.voice.channel.connect()
            else:
                await ctx.send("You are not connected to a voice channel.")
                raise commands.CommandError("Author not connected to a voice channel.")
        elif ctx.voice_client.is_playing():
            ctx.voice_client.stop()

bot = commands.Bot(command_prefix=commands.when_mentioned_or("!"),
                   description='Relatively simple music bot example')

@bot.event
async def on_ready():
    print('Logged in as {0} ({0.id})'.format(bot.user))
    print('------')

bot.add_cog(Music(bot))
bot.run('token')

This time it is taken from github. From here, you may want to make it easier to see with embed. (Sorry for throwing)

Run

When executed, the following commands can be used. Connect to join [channel] / [channel] Play the link specified by yt [url] / [url] * [url] is also searched by song title etc. Play the link specified by stream [url] / [url] * I don't know this Adjust to the volume specified by volume [volume] / [volume] stop / Disconnect from VC

bonus

The previous throwing makes it meaningless to write an article (?) I rewrote the code a little to make it easier to use.

    @commands.command(aliases=["p"])
    async def play(self, ctx, *, url):
        channel = ctx.author.voice.channel
        if channel is None:
            return await ctx.send("Not connected to VC.")

        await channel.connect()
        async with ctx.typing():
            player = await YTDLSource.from_url(url, loop=self.bot.loop)
            ctx.voice_client.play(player, after=lambda e: print('Player error: %s' % e) if e else None)
            await ctx.send("Playing:{}".format(player.title))
    @commands.command(aliases=["vol"])
    async def volume(self, ctx, volume: int):
        channel = ctx.author.voice.channel
        if channel is None:
            return await ctx.send(Not connected to VC)

        ctx.voice_client.source.volume = volume / 100
        await ctx.send("Volume change:{}".format(volume))
    @commands.command(aliases=["bye","disconnect"])
    async def stop(self, ctx):
        channel = ctx.author.voice.channel
        if channel is None:
            return await ctx.send(Not connected to VC)

        await ctx.voice_client.disconnect()
        await ctx.send("I left the VC.")

As an improvement of the above code ・ Abolish join ・ Connect to VC with play ・ Check if all are connected to VC I made some improvements.

Finally

How was it? I wasn't used to it yet, but I was able to finish writing it safely! Nowadays, bots such as Rythm and MEE6 are famous, but we are aiming for a bot that is comparable to that! It will be an advertisement, but I would be grateful if you could introduce my bot! You can try out bot features and have invitation links on the Support Server (https://discord.gg/bTSHEUsjmy). I hope you will take a look. I'm thinking of making articles gradually, but I haven't written anything so please let me know if there is anything.

Have a nice year!

Recommended Posts

[Latest version] Play YouTube videos on discord.py!
[Latest version] Let the bot speak at regular intervals on discord.py
Search and play YouTube videos in Python
Use the latest version of PyCharm on Ubuntu
Install the latest version of CMake on Ubuntu 18.04.4 LTS
Notes on upgrading discord.py from async to rewrite version
Play chess on Discord
Play youtube in python
YouTube #NowPlaying on Pythonista
Put the latest version of Python on linux (Debian) on Chromebook
Install the latest version of Git on your Linux server