Как написать бота для дискорда на python для музыки

In this tutorial, we’ll make a Python Discord bot that can play music in the voice channels and send GIFs. Discord is an instant messaging and digital distribution platform designed for creating communities. Users can easily enter chat rooms, initiate video calls, and create multiple groups for messaging friends.

We’ll skip the basics and jump straight over to the music playing. Check out this Medium article to catch up on the basics of setting up your bot. In the end, our Python Discord bot will look like the cover image of this article!

Before we dive in: remember to allow Administrator permissions for the bot.

Thanks to Rohan Krishna Ullas, who wrote this guest tutorial! Make sure to check out his Medium profile for more articles from him. If you want to write for Python Land too, please contact us.

Table of Contents

  • 1 Part 1: Importing all the libraries
  • 2 Part 2: Using youtube_dl to download audio
  • 3 Part 3: Adding commands to the Python Discord bot
  • 4 Part 4: Running the Python Discord bot locally
  • 5 Bonus: send GIFs on start-up and print server details

Part 1: Importing all the libraries

First, create a virtual environment and install the requirements:

discord==1.0.1
discord.py==1.6.0
python-dotenv==0.15.0
youtube-dl==2021.2.10

Next, let’s set up the .env file for our project. Create a .env file so that we can separate the environment configuration variables (these are variables whose values are set outside the program) from the main code:

discord_token = "copy_paste_your_bot_token_here"

Then use Python import to load all the needed modules in the main file app.py:

import discord
from discord.ext import commands,tasks
import os
from dotenv import load_dotenv
import youtube_dl

The module youtube_dl is an open-source download manager for video and audio content from YouTube and other video hosting websites.

Now we need to set intents for our bot. Intents allow a bot to subscribe to specific buckets of events, allowing developers to choose which events the bot listens to and to which it doesn’t. For example, sometimes we want the bot to listen to only messages and nothing else.

load_dotenv()

# Get the API token from the .env file.
DISCORD_TOKEN = os.getenv("discord_token")

intents = discord.Intents().all()
client = discord.Client(intents=intents)
bot = commands.Bot(command_prefix='!',intents=intents)

Part 2: Using youtube_dl to download audio

The next step in building our Python Discord bot is dealing with the part that actually downloads the audio file from the video link we provide. Please note that this bo is just a demonstration. It’s not illegal to download from YouTube for personal use according to this article, but it might be against the YouTube Terms Of Service. Please be sensible and use this for personal use only.

youtube_dl.utils.bug_reports_message = lambda: ''

ytdl_format_options = {
    'format': 'bestaudio/best',
    '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 = ""

    @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['title'] if stream else ytdl.prepare_filename(data)
        return filename

The from_url() method of YTDLSource class takes in the URL as a parameter and returns the filename of the audio file which gets downloaded. You can read the youtube_dl documentation at their GitHub repository.

Part 3: Adding commands to the Python Discord bot

Now let’s add the join() method to tell the bot to join the voice channel and the leave() method to tell the bot to disconnect:

@bot.command(name='join', help='Tells the bot to join the voice channel')
async def join(ctx):
    if not ctx.message.author.voice:
        await ctx.send("{} is not connected to a voice channel".format(ctx.message.author.name))
        return
    else:
        channel = ctx.message.author.voice.channel
    await channel.connect()

@bot.command(name='leave', help='To make the bot leave the voice channel')
async def leave(ctx):
    voice_client = ctx.message.guild.voice_client
    if voice_client.is_connected():
        await voice_client.disconnect()
    else:
        await ctx.send("The bot is not connected to a voice channel.")

Here we first check if the user who wants to play music has already joined the voice channel or not. If not, we tell the user to join first.

Awesome! Give yourself a pat on the back if you’ve reached this far! You’re doing great. In the next step, we’ll add the following methods:

  • play()
  • pause()
  • resume()
  • stop()
@bot.command(name='play_song', help='To play song')
async def play(ctx,url):
    try :
        server = ctx.message.guild
        voice_channel = server.voice_client

        async with ctx.typing():
            filename = await YTDLSource.from_url(url, loop=bot.loop)
            voice_channel.play(discord.FFmpegPCMAudio(executable="ffmpeg.exe", source=filename))
        await ctx.send('**Now playing:** {}'.format(filename))
    except:
        await ctx.send("The bot is not connected to a voice channel.")


@bot.command(name='pause', help='This command pauses the song')
async def pause(ctx):
    voice_client = ctx.message.guild.voice_client
    if voice_client.is_playing():
        await voice_client.pause()
    else:
        await ctx.send("The bot is not playing anything at the moment.")
    
@bot.command(name='resume', help='Resumes the song')
async def resume(ctx):
    voice_client = ctx.message.guild.voice_client
    if voice_client.is_paused():
        await voice_client.resume()
    else:
        await ctx.send("The bot was not playing anything before this. Use play_song command")

@bot.command(name='stop', help='Stops the song')
async def stop(ctx):
    voice_client = ctx.message.guild.voice_client
    if voice_client.is_playing():
        await voice_client.stop()
    else:
        await ctx.send("The bot is not playing anything at the moment.")

At this point, we need to have the ffmpeg binary in the base directory. It can be downloaded from https://ffmpeg.org/. In this case, I used the exe since I’m using a Windows machine.

Part 4: Running the Python Discord bot locally

Add the final piece of code to start the bot and it’s done:

if __name__ == "__main__" :
    bot.run(DISCORD_TOKEN)

To deploy the bot locally, activate the virtual environment and run the app.py file:

(venv1) C:GithubDiscord-Bot>python app.py

Bonus: send GIFs on start-up and print server details

In this bonus section, we will set up our bot to listen to events such as start-up. This example sends a previously downloaded GIF image to the text channel when the bot is activated:

@bot.event
async def on_ready():
    for guild in bot.guilds:
        for channel in guild.text_channels :
            if str(channel) == "general" :
                await channel.send('Bot Activated..')
                await channel.send(file=discord.File('add_gif_file_name_here.png'))
        print('Active in {}n Member Count : {}'.format(guild.name,guild.member_count))

To print server details such as owner name, the number of users, and a server id, we can add a bot command ‘where_am_i’:

@bot.command(help = "Prints details of Server")
async def where_am_i(ctx):
    owner=str(ctx.guild.owner)
    region = str(ctx.guild.region)
    guild_id = str(ctx.guild.id)
    memberCount = str(ctx.guild.member_count)
    icon = str(ctx.guild.icon_url)
    desc=ctx.guild.description
    
    embed = discord.Embed(
        title=ctx.guild.name + " Server Information",
        description=desc,
        color=discord.Color.blue()
    )
    embed.set_thumbnail(url=icon)
    embed.add_field(name="Owner", value=owner, inline=True)
    embed.add_field(name="Server ID", value=guild_id, inline=True)
    embed.add_field(name="Region", value=region, inline=True)
    embed.add_field(name="Member Count", value=memberCount, inline=True)

    await ctx.send(embed=embed)

    members=[]
    async for member in ctx.guild.fetch_members(limit=150) :
        await ctx.send('Name : {}t Status : {}n Joined at {}'.format(member.display_name,str(member.status),str(member.joined_at)))

@bot.command()
async def tell_me_about_yourself(ctx):
    text = "My name is WallE!n I was built by Kakarot2000. At present I have limited features(find out more by typing !help)n :)"
    await ctx.send(text)

This is what this will look like:

Printing server details — Image by author

You can view and clone the complete results from my Discord-Bot GitHub Repository.

That’s it! We made a Python Discord bot. Thank you for reading, and don’t hesitate to leave a reply or ask your questions in the comments section.

Our premium courses offer a superior user experience with small, easy-to-digest lessons, progress tracking, quizzes to test your knowledge, and practice sessions. Each course will earn you a downloadable course certificate.

# -*- coding: utf-8 -*- «»» Copyright (c) 2019 Valentin B. A simple music bot written in discord.py using youtube-dl. Though it’s a simple example, music bots are complex and require much time and knowledge until they work perfectly. Use this as an example or a base for your own bot and extend it as you want. If there are any bugs, please let me know. Requirements: Python 3.5+ pip install -U discord.py pynacl youtube-dl You also need FFmpeg in your PATH environment variable or the FFmpeg.exe binary in your bot’s directory on Windows. «»» import asyncio import functools import itertools import math import random import discord import youtube_dl from async_timeout import timeout from discord.ext import commands # Silence useless bug reports messages youtube_dl.utils.bug_reports_message = lambda: » class VoiceError(Exception): pass class YTDLError(Exception): pass class YTDLSource(discord.PCMVolumeTransformer): YTDL_OPTIONS = { ‘format’: ‘bestaudio/best’, ‘extractaudio’: True, ‘audioformat’: ‘mp3’, ‘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’, } FFMPEG_OPTIONS = { ‘before_options’: ‘-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5’, ‘options’: ‘-vn’, } ytdl = youtube_dl.YoutubeDL(YTDL_OPTIONS) def __init__(self, ctx: commands.Context, source: discord.FFmpegPCMAudio, *, data: dict, volume: float = 0.5): super().__init__(source, volume) self.requester = ctx.author self.channel = ctx.channel self.data = data self.uploader = data.get(‘uploader’) self.uploader_url = data.get(‘uploader_url’) date = data.get(‘upload_date’) self.upload_date = date[6:8] + ‘.’ + date[4:6] + ‘.’ + date[0:4] self.title = data.get(‘title’) self.thumbnail = data.get(‘thumbnail’) self.description = data.get(‘description’) self.duration = self.parse_duration(int(data.get(‘duration’))) self.tags = data.get(‘tags’) self.url = data.get(‘webpage_url’) self.views = data.get(‘view_count’) self.likes = data.get(‘like_count’) self.dislikes = data.get(‘dislike_count’) self.stream_url = data.get(‘url’) def __str__(self): return ‘**{0.title}** by **{0.uploader}**’.format(self) @classmethod async def create_source(cls, ctx: commands.Context, search: str, *, loop: asyncio.BaseEventLoop = None): loop = loop or asyncio.get_event_loop() partial = functools.partial(cls.ytdl.extract_info, search, download=False, process=False) data = await loop.run_in_executor(None, partial) if data is None: raise YTDLError(‘Couldnt find anything that matches `{}`’.format(search)) if ‘entries’ not in data: process_info = data else: process_info = None for entry in data[‘entries’]: if entry: process_info = entry break if process_info is None: raise YTDLError(‘Couldnt find anything that matches `{}`’.format(search)) webpage_url = process_info[‘webpage_url’] partial = functools.partial(cls.ytdl.extract_info, webpage_url, download=False) processed_info = await loop.run_in_executor(None, partial) if processed_info is None: raise YTDLError(‘Couldnt fetch `{}`’.format(webpage_url)) if ‘entries’ not in processed_info: info = processed_info else: info = None while info is None: try: info = processed_info[‘entries’].pop(0) except IndexError: raise YTDLError(‘Couldnt retrieve any matches for `{}`’.format(webpage_url)) return cls(ctx, discord.FFmpegPCMAudio(info[‘url’], **cls.FFMPEG_OPTIONS), data=info) @staticmethod def parse_duration(duration: int): minutes, seconds = divmod(duration, 60) hours, minutes = divmod(minutes, 60) days, hours = divmod(hours, 24) duration = [] if days > 0: duration.append(‘{} days’.format(days)) if hours > 0: duration.append(‘{} hours’.format(hours)) if minutes > 0: duration.append(‘{} minutes’.format(minutes)) if seconds > 0: duration.append(‘{} seconds’.format(seconds)) return ‘, ‘.join(duration) class Song: __slots__ = (‘source’, ‘requester’) def __init__(self, source: YTDLSource): self.source = source self.requester = source.requester def create_embed(self): embed = (discord.Embed(title=‘Now playing’, description=‘«`cssn{0.source.title}n«`’.format(self), color=discord.Color.blurple()) .add_field(name=‘Duration’, value=self.source.duration) .add_field(name=‘Requested by’, value=self.requester.mention) .add_field(name=‘Uploader’, value=‘[{0.source.uploader}]({0.source.uploader_url})’.format(self)) .add_field(name=‘URL’, value=‘[Click]({0.source.url})’.format(self)) .set_thumbnail(url=self.source.thumbnail)) return embed class SongQueue(asyncio.Queue): def __getitem__(self, item): if isinstance(item, slice): return list(itertools.islice(self._queue, item.start, item.stop, item.step)) else: return self._queue[item] def __iter__(self): return self._queue.__iter__() def __len__(self): return self.qsize() def clear(self): self._queue.clear() def shuffle(self): random.shuffle(self._queue) def remove(self, index: int): del self._queue[index] class VoiceState: def __init__(self, bot: commands.Bot, ctx: commands.Context): self.bot = bot self._ctx = ctx self.current = None self.voice = None self.next = asyncio.Event() self.songs = SongQueue() self._loop = False self._volume = 0.5 self.skip_votes = set() self.audio_player = bot.loop.create_task(self.audio_player_task()) def __del__(self): self.audio_player.cancel() @property def loop(self): return self._loop @loop.setter def loop(self, value: bool): self._loop = value @property def volume(self): return self._volume @volume.setter def volume(self, value: float): self._volume = value @property def is_playing(self): return self.voice and self.current async def audio_player_task(self): while True: self.next.clear() if not self.loop: # Try to get the next song within 3 minutes. # If no song will be added to the queue in time, # the player will disconnect due to performance # reasons. try: async with timeout(180): # 3 minutes self.current = await self.songs.get() except asyncio.TimeoutError: self.bot.loop.create_task(self.stop()) return self.current.source.volume = self._volume self.voice.play(self.current.source, after=self.play_next_song) await self.current.source.channel.send(embed=self.current.create_embed()) await self.next.wait() def play_next_song(self, error=None): if error: raise VoiceError(str(error)) self.next.set() def skip(self): self.skip_votes.clear() if self.is_playing: self.voice.stop() async def stop(self): self.songs.clear() if self.voice: await self.voice.disconnect() self.voice = None class Music(commands.Cog): def __init__(self, bot: commands.Bot): self.bot = bot self.voice_states = {} def get_voice_state(self, ctx: commands.Context): state = self.voice_states.get(ctx.guild.id) if not state: state = VoiceState(self.bot, ctx) self.voice_states[ctx.guild.id] = state return state def cog_unload(self): for state in self.voice_states.values(): self.bot.loop.create_task(state.stop()) def cog_check(self, ctx: commands.Context): if not ctx.guild: raise commands.NoPrivateMessage(‘This command cant be used in DM channels.’) return True async def cog_before_invoke(self, ctx: commands.Context): ctx.voice_state = self.get_voice_state(ctx) async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError): await ctx.send(‘An error occurred: {}’.format(str(error))) @commands.command(name=‘join’, invoke_without_subcommand=True) async def _join(self, ctx: commands.Context): «»»Joins a voice channel.»»» destination = ctx.author.voice.channel if ctx.voice_state.voice: await ctx.voice_state.voice.move_to(destination) return ctx.voice_state.voice = await destination.connect() @commands.command(name=‘summon’) @commands.has_permissions(manage_guild=True) async def _summon(self, ctx: commands.Context, *, channel: discord.VoiceChannel = None): «»»Summons the bot to a voice channel. If no channel was specified, it joins your channel. «»» if not channel and not ctx.author.voice: raise VoiceError(‘You are neither connected to a voice channel nor specified a channel to join.’) destination = channel or ctx.author.voice.channel if ctx.voice_state.voice: await ctx.voice_state.voice.move_to(destination) return ctx.voice_state.voice = await destination.connect() @commands.command(name=‘leave’, aliases=[‘disconnect’]) @commands.has_permissions(manage_guild=True) async def _leave(self, ctx: commands.Context): «»»Clears the queue and leaves the voice channel.»»» if not ctx.voice_state.voice: return await ctx.send(‘Not connected to any voice channel.’) await ctx.voice_state.stop() del self.voice_states[ctx.guild.id] @commands.command(name=‘volume’) async def _volume(self, ctx: commands.Context, *, volume: int): «»»Sets the volume of the player.»»» if not ctx.voice_state.is_playing: return await ctx.send(‘Nothing being played at the moment.’) if 0 > volume > 100: return await ctx.send(‘Volume must be between 0 and 100’) ctx.voice_state.volume = volume / 100 await ctx.send(‘Volume of the player set to {}%’.format(volume)) @commands.command(name=‘now’, aliases=[‘current’, ‘playing’]) async def _now(self, ctx: commands.Context): «»»Displays the currently playing song.»»» await ctx.send(embed=ctx.voice_state.current.create_embed()) @commands.command(name=‘pause’) @commands.has_permissions(manage_guild=True) async def _pause(self, ctx: commands.Context): «»»Pauses the currently playing song.»»» if not ctx.voice_state.is_playing and ctx.voice_state.voice.is_playing(): ctx.voice_state.voice.pause() await ctx.message.add_reaction(‘⏯’) @commands.command(name=‘resume’) @commands.has_permissions(manage_guild=True) async def _resume(self, ctx: commands.Context): «»»Resumes a currently paused song.»»» if not ctx.voice_state.is_playing and ctx.voice_state.voice.is_paused(): ctx.voice_state.voice.resume() await ctx.message.add_reaction(‘⏯’) @commands.command(name=‘stop’) @commands.has_permissions(manage_guild=True) async def _stop(self, ctx: commands.Context): «»»Stops playing song and clears the queue.»»» ctx.voice_state.songs.clear() if not ctx.voice_state.is_playing: ctx.voice_state.voice.stop() await ctx.message.add_reaction(‘⏹’) @commands.command(name=‘skip’) async def _skip(self, ctx: commands.Context): «»»Vote to skip a song. The requester can automatically skip. 3 skip votes are needed for the song to be skipped. «»» if not ctx.voice_state.is_playing: return await ctx.send(‘Not playing any music right now…’) voter = ctx.message.author if voter == ctx.voice_state.current.requester: await ctx.message.add_reaction(‘⏭’) ctx.voice_state.skip() elif voter.id not in ctx.voice_state.skip_votes: ctx.voice_state.skip_votes.add(voter.id) total_votes = len(ctx.voice_state.skip_votes) if total_votes >= 3: await ctx.message.add_reaction(‘⏭’) ctx.voice_state.skip() else: await ctx.send(‘Skip vote added, currently at **{}/3**’.format(total_votes)) else: await ctx.send(‘You have already voted to skip this song.’) @commands.command(name=‘queue’) async def _queue(self, ctx: commands.Context, *, page: int = 1): «»»Shows the player’s queue. You can optionally specify the page to show. Each page contains 10 elements. «»» if len(ctx.voice_state.songs) == 0: return await ctx.send(‘Empty queue.’) items_per_page = 10 pages = math.ceil(len(ctx.voice_state.songs) / items_per_page) start = (page 1) * items_per_page end = start + items_per_page queue = » for i, song in enumerate(ctx.voice_state.songs[start:end], start=start): queue += ‘`{0}.` [**{1.source.title}**]({1.source.url})n.format(i + 1, song) embed = (discord.Embed(description=‘**{} tracks:**nn{}’.format(len(ctx.voice_state.songs), queue)) .set_footer(text=‘Viewing page {}/{}’.format(page, pages))) await ctx.send(embed=embed) @commands.command(name=‘shuffle’) async def _shuffle(self, ctx: commands.Context): «»»Shuffles the queue.»»» if len(ctx.voice_state.songs) == 0: return await ctx.send(‘Empty queue.’) ctx.voice_state.songs.shuffle() await ctx.message.add_reaction(‘✅’) @commands.command(name=‘remove’) async def _remove(self, ctx: commands.Context, index: int): «»»Removes a song from the queue at a given index.»»» if len(ctx.voice_state.songs) == 0: return await ctx.send(‘Empty queue.’) ctx.voice_state.songs.remove(index 1) await ctx.message.add_reaction(‘✅’) @commands.command(name=‘loop’) async def _loop(self, ctx: commands.Context): «»»Loops the currently playing song. Invoke this command again to unloop the song. «»» if not ctx.voice_state.is_playing: return await ctx.send(‘Nothing being played at the moment.’) # Inverse boolean value to loop and unloop. ctx.voice_state.loop = not ctx.voice_state.loop await ctx.message.add_reaction(‘✅’) @commands.command(name=‘play’) async def _play(self, ctx: commands.Context, *, search: str): «»»Plays a song. If there are songs in the queue, this will be queued until the other songs finished playing. This command automatically searches from various sites if no URL is provided. A list of these sites can be found here: https://rg3.github.io/youtube-dl/supportedsites.html «»» if not ctx.voice_state.voice: await ctx.invoke(self._join) async with ctx.typing(): try: source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop) except YTDLError as e: await ctx.send(‘An error occurred while processing this request: {}’.format(str(e))) else: song = Song(source) await ctx.voice_state.songs.put(song) await ctx.send(‘Enqueued {}’.format(str(source))) @_join.before_invoke @_play.before_invoke async def ensure_voice_state(self, ctx: commands.Context): if not ctx.author.voice or not ctx.author.voice.channel: raise commands.CommandError(‘You are not connected to any voice channel.’) if ctx.voice_client: if ctx.voice_client.channel != ctx.author.voice.channel: raise commands.CommandError(‘Bot is already in a voice channel.’) bot = commands.Bot(‘music.’, description=‘Yet another music bot.’) bot.add_cog(Music(bot)) @bot.event async def on_ready(): print(‘Logged in as:n{0.user.name}n{0.user.id}’.format(bot)) bot.run(‘Token’)

Do you find it surprising that Discord has become well-known in the digital and business world? There are good reasons why it currently dominates the social media scene. It enhances social media interaction, chatting, gaming, or simply interacting with business organizations.

Millions of people use Discord daily, and a considerable percentage regularly automate tasks using bots. These bots are making Discord one of the best social messaging platforms for different industries. 

 Let’s dive in!

Table of Contents

  • What is Discord? 
  • Why is Discord Popular? 
  • Terms Associated With Discord 
  • Is Discord Free?
  • What is a Discord Bot? 
  • Benefits of Discord Bots
  • Steps to Creating a Discord Bot With Python using Nextcord.py

    • Sample Codes for Discord Bots in Python

      • A. Sample Codes to make Discord Bots Respond to Greetings
      • B. Sample Codes to Make a Discord Bots Send Gifs
      • C. Sample Codes to make Discord Bots Play Music
  • Conclusion

What is Discord?

Discord is a social application that offers free phone, video, and text communication. It is one of the most well-known social networking sites used by millions of people to communicate and hang out with their friends and neighbors

People frequently use Discord to talk about a range of subjects, such as family vacations, homework assistance, NFTs, cryptocurrencies, the Metaverse, and mental health support. Any sized group of people can call it home, but the tiniest, chattiest groups use it the most regularly.

It gives public communities the platform to interact. People have complete control over who they interact with and how they use Discord because all discussions are opt-in.

It includes servers that are exclusive and private channels where communities and friendship circles can communicate and socialize and hold events. 

Discord, however, swiftly gained popularity among gamers after its initial 2015 release by Jason Citron and Stanislav Vishnevskiy. The two co-founders wanted to create a better communication tool while working in the video game industry.

Why is Discord Popular?

Even though it has been seeing yearly user growth since its launch in 2015, Discord’s popularity increased in 2018 as streaming and online gaming began to expand quickly.

Discord’s connection with Xbox was the second significant action following its launch. It was a truly great experience for users to connect their Xbox Live accounts with their Discord servers. But by 2020, everyone was familiar with Discord.

Its fast popularity is due to the convenience it provides to players and streamers worldwide. Since then, Discord has become a well-liked platform for connecting with loved ones and having simple conversations.

Discord achieved quick popularity, unlike many other similar messaging applications. Because it serves as a home for all communities and friendship groups, people adore Discord. They may be themselves there while socializing with others who appreciate the same things they do.

On Discord, conversations are stimulated by common interests from people who share a similar view on a topic. Discord provides different communication options for like minds to interact in the best way they can use to understand themselves.

Terms Associated With Discord

Discord users occasionally utilize some terminology when referring to some of the activities on the platform. Below are examples of some of these terminologies.  

  • Channel: Text and voice channels are servers Discord relies on to transmit information. Users can exchange photographs, upload files, and publish messages in text channels at any time for other people to see. Additionally, users can go “live” in voice channels, where they can show their screen with peers and interact through voice or video chat in real-time.
  • DMs and GDMs: Users can initiate voice or video calls as well as send private messages to other users as direct messages (DM). Group Direct Messages are private and accessible only by invitation from a group member.
  • Server: Discord’s spaces are called servers. Particular communities and cliques create them. A new server can be set up by any user for no cost, and they can invite their friends to join.
  • Nitro: Nitro is Discord’s premium subscription service. It enables users to customize Discord Tag, use custom emotes on every server, have a higher file upload cap, and discounted Server Boosts. 
  • Server Boosts:  Dual to Nitro, Server Boosts grant servers exclusive benefits, including more personalized emotes, improved voice and video quality, and the capacity to set a personalized invite link.
  • Student Hubs: Students can choose servers for study groups or classes, connect with other verified students, and share their own servers with other students using Discord Hubs for Students. 

Is Discord Free?

Discord is without communication limitations. Access to communities is unrestricted, and starting your server is also cost-free.

You’ve probably heard of Discord bots if you use the platform for business purposes. With the help of these AI-powered bots, you can carry out different tasks, such as welcoming new users or people in search of your service.

It is a helpful tactic for online marketers who are learning how to use it to their advantage. Discord bots may be the way to go if you’re searching for a distinctive and interesting approach to interacting with your community.

What is a Discord Bot?

Discord bots are top A.I.s used by marketers and business owners to perform a range of automated tasks on the server. Discord bots can manage the discussion, filter material, automatically welcome new users, and ban disruptive individuals. Some bots even add music or games to your server.

They are amiable AI that supports server management or service enhancement. Discord bots are pre-made and free to download — no computer skills necessary. 

You can back up your business information that the bot emulates in a database.

MongoDB is a popular database you can use for this purpose, although storing data in MongoDB is an activity among experienced programmers coding these bots. So this may require that only top programmers handle this process.

Benefits of Discord Bots

  • Developing an active community is made simpler by Discord bots.
  • When you’re briefly unavailable online, it takes your place. It acquaints new players with your server and moderately satisfies some of their needs.
  • You can utilize them to include games, music, memes, and other fun material.
  • Discord bots help to enhance your server and foster a better community, making users stay and engage with you more.

Steps to Creating a Discord Bot With Python using Nextcord.py

First, you need to enable the bot from the Discord application. Make your Python environment function going there next. Then go to your Python environment to make it functional.

To set everything up, you do need a basic understanding of programming, although the complexity of the code may vary depending on the type of bot you’re building.

Let’s look at some of the prerequisites for getting started. You must first have a Discord account, which you undoubtedly already do. If not, visit the Discord webpage to create one at no cost. The Discord client is also available for download, and you may use it on a phone or your gaming laptop.

To start with the bots creation, let’s enable it first from the server. 

  • Visit the official website of Discord to register; or log in if you are an old user
  • Select “New Application” and then enter a name for the program before clicking “Create.”
  • Create a Bot User by visiting the “Bot” page and clicking “Add Bot.”
  • To move forward, click “Yes, go ahead!”
  • Check the Public Bot button.
  • Do not check the OAuth2 Code button unless you’re developing a service that requires you to. If you’re unsure of its functionality, leave it unchecked.
  • If you don’t already have a token, just hit the Reset button to create one. Keep this token ID safe because we’ll need it later.

So that’s it, you can log in to your newly created bot account.

Even though you created a bot user, it isn’t truly present in any servers. We need to do one more thing.

  • Visit the application page, and click on your newly created bot page
  • Select the “OAuth2” tab.
  • To discover your CLIENT ID, locate the OAuth2 option in the menu on the left sidebar and click on it. Ensure you copy the lengthy string of numbers and paste them into the URL.
  • You’ll notice a message verifying the bot’s arrival after you add it to your server. The bot icon appears on the right-hand side of your Discord application.

It’s time to finish developing your app. To test the functionality of your bot, open the Python source code.

Sample Codes for Discord Bots in Python

A. Sample Codes to make Discord Bots Respond to Greetings

from nextcord.ext import commands



bot = commands.Bot(command_prefix="!")

# make the bot to greet the user

@bot.command(name="hi")
async def SendMsg(ctx):
  await ctx.send('Hello, Who is am i with on the best chat platform?')

  @bot.event
  async def on_ready():
    print(f"logged in as: {bot.user.name}")

    if __name__ == '__main__':
      #please paste your own special token here
      bot.run("OTYwrdgffhhHHVGYFTFgjh.YuygTY.urPO_JSSDvbHFJBVssdfdgbJ")

#run your program and go back to discord

B. Sample Codes to Make a Discord Bots Send Gifs

from nextcord.ext import commands


bot = commands.Bot(command_prefix="dog ")

#The aim is to make our bot send dog pictures whenever we enter dog pic
#We will be visiting the Dog API website to copy the APi address that returns a JSON containing the link
# we will be using a python module called request to make this request from the dog server

  @bot.command(name="pic")
  async def Dog(ctx):
    response = request.get("https://dog.ceo/api/breeds/image/random")
    Pic_link = response.json()["message"]
    await ctx.send(Pic_link)

#run your program and go back to discord to test, on discord type dog pic

C. Sample Codes to make Discord Bots Play Music

import nextcord
import asyncio
import youtube_dl
from nextcord.ext import commands

#remember to do pip install youtube_dl if you have not

youtube_dl.utils.bug_reports_message = lambda: ""


#this acts like a schema for youtube files, just copy and paste on this format 
ytdl_format_options = {
  
  "format": "bestaudio/best",

  "outtmpl": "%(extractor)s-%(id)s-%(title)s.%(ext)s",

  "restrictfilename": True,

  "noplaylist": True,

  "nocheckcertificate": True,

  "ignoreerrors": False,

  "logtostderr": False,

  "quiet": True,

  "no_warning": True,

  "default_search": "auto",

  "source_address": "0.0.0.0",

}

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

ytdl = youtube_dl.YoutubeDL(ytdl_format_options)


#this function will get a download from a Url to allow the bot get youtube Url and download that and play it through the bot
class YTDLSource(nextcord.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")

#this method is basically returning the file so it can be played through the bot
  @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:
      data = data["entries"][0]

    filename = data["url"] if stream else ytdl.prepare_filename(data)
    return cls(nextcord.FFmpegAudio(filename, **ffmpeg_options), data=data)

#this class holds all the commands for the music bot
class Music(commands.Cog):
  def __init__(self, bot):
    self.bot = bot


#this method joins the command and makes the connection to the channel(on your bot enter $join to join channel) 
  @commands.command()
  async def join(self, ctx, *, channel: nextcord.VoiceChannel):
    if ctx.voice_client is not None:
      return await ctx.voice_client.move_to(channel)
    await channel.connect()

#method to automate the bot to play the file it fetches
  @commands.command()
  async def play(self, ctx, *, query):
    source = nextcord.PCMVolumeTransformer(nextcord.FFmpegPCMAudio(query))
    ctx.voice_client.play(source, after= lambda e: print(f"player error": {e}") if e else None)

    await ctx.send(f"Now playing: {query}")
#this command gets the YouTube link and makes the download before the music plays
  @commands.command()
  async def yt(self, ctx, *, url):
    player = await YTDLSource.from_url(url, loop=self.bot.loop)
    ctx.voice_client.play(
        player, after=lambda e: print(f"Player error: {e}") if e else None
    )

    await ctx.send(f"Now playing...: {player.title}")

#the stream command ensures that the bot do not make downloads before playing the songs if it receives a stream command
  @commands.command()
  async def stream(self,ctx, *, url):
    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(f"player error: {e}") if e elase None
      )

    await ctx.send(f"now playing: {player.title}")
  
#this method stops the music 
  @commands.command()
  async def stop(self, ctx):
    await ctx.voice_client.disconnect()

  @play.before_invoke
  @yt.before_invoke
  @stream.before_invoke
#check if the user gets is connected or not
  async def e_voice(self, ctx):
    if ctx.voice_client id None:
      if ctx.author.voice:
        await ctx.author.voice.channel.connect()
      else:
        await ctx.send("oppps, you are not connected to a voice channel currently")
        raise commands.CommandError("Author is absent on a voice channel")
    elif ctx.voice_client.is_playing():
      ctx.voice_client.stop()


#set up the bot so that we can actually run it
intents = nextcord.Intents.default()
intents.message_content = True

bot = commands.Bot(command_prefix = "!", intents= intents) 
bot.add_cog(Music(bot))

#copy the secret keys for the hot app and paste here 
bot.run("OTYwrdgffhhHHVGYFTFgjh.YuygTY.urPO_JSSDvbHFJBVssdfdgbJ")


#at the end of the code, a file will be downloaded on your visit when you run the code for the first time

Conclusion

Using Discord bots is a cutting-edge and effective digital marketing tactic. Discord bots make your discord server lively and active. Additionally, they operate round-the-clock.

Dive deeper into creating Discord Bots in Python using Discord.py.

Cover image for How to set up a Discord music bot (Updated December 2021)

Nir

Nir

Posted on Sep 13, 2019

• Updated on Dec 27, 2021



 



 



 



 



 

 

Setting up a music bot isn’t easy since it requires lots of different things to be installed. In this guide I will list all the requirements and provide you with the code you need. Make sure you follow all the steps :)

Let’s start!

Create a bot

First we need to create the bot, go here and make sure you’re logged in. Click on New Application and give your bot a name.
Go to the «Bot» tab on the left and click Add Bot under the «BUILD-A-BOT» tab. Copy the token and save it because we will need it for later.
Copy the Application ID under the «General Information» tab and save it for later as well.

Now click on the «OAuth2» tab and then on «URL Generator». Under «Scopes», check «bot» and on «applications.commands». Under «Bot Permissions», check «Administrator». Now copy the URL under «Generated URL» and paste it into your browser in order to invite your newly created bot to your Discord server!

Code Editor

A code editor let’s us write and modify code. The code editor I use and recommend is Visual Studio Code.
You can also use other great editors like Sublime Text and Atom.

Node.js and npm

Node.js is a JavaScript runtime. It basically lets us run JavaScript code on our machine. We also use its package ecosystem, npm, which we will discuss next.
Download Node.js from its official website (LTS or latest).
To check if you installed it correctly, open your terminal(cmd or bash depending on which OS you are using), and run node -v, you should get a number back. If you’re struggling with installing Node, check out this guide.
nom comes installed with Node.js, we will use npm later to install dependencies.

Git

Git is an open source version control system. It helps developers to manage projects by keeping track of the entire history of a project and makes it easy to add features without worrying about breaking the entire codebase. We will use Git in order to obtain code for our bot from GitHub. GitHub is a hosting service for Git repositories. You can learn more about Git and Github from this superb article.

If you’re on Windows, install Git from here. For macOS users, install Xcode and then hit git —version, it’ll prompt you to install it. If you’re using Linux based OS, hit sudo dnf install git-all or sudo apt install git-all for debian.

Java 13

Download Java 13 from here, make sure you download the correct one for your Operating System.

Cloning the repository

Go to your terminal(cmd, git bash or bash), you probably see on the left that you are now in your user folder(C:Users/»username»). Enter cd Desktop to go to your Desktop. Then ‘git clone https://github.com/galnir/Master-Bot‘. You are cloning(copying) the repository from GitHub so you can use its code.

Getting Lavalink

Download the latest Lavalink jar file from here (under assets). Place the jar file in the root directory of the project (same folder as index.js and package.json)

Application.yml

Create a file named application.yml in the same folder you placed the jar file from before. Copy everything from this example to your application.yml

Tokens

For everything to function we need the following tokens:

  • The bots discord ID (saved from the first section)
  • The bots token (saved from the first section)
  • A Spotify client ID
  • A Spotify client secret

In order to generate the last 2 tokens you need to create a Spotify account and login to the dev dashboard
After you login, simply create an app and copy the client ID and secret.

Config.json

In the root directory of the project create a file named config.json and have it look like this:

{
  "client_id": "the-bots-discord-id",
  "token": "Your-Bot-Token",
  "lava_host": "0.0.0.0",
  "lava_pass": "youshallnotpass",
  "spotify_client_id": "get-it-from-spotify-dev",
  "spotify_client_secret": "get-it-from-spotify-dev"
}

Enter fullscreen mode

Exit fullscreen mode

Put every token you generated in its place surrounded by quotes

Running the bot

Open a terminal in the root directory of the project and run java -jar Lavalink.jar.
Now open another terminal instance in the same folder and run node index.js

After running both commands you should be able to run music commands using the new Slash feature! Simply type / in a text channel and you should see the command list!

If you have any questions/issues you can comment here or open an issue in the repo. Also don’t forget to leave a star in the repo if you found it helpful :)

Bot Repo: https://github.com/galnir/Master-Bot
Cover image by Malte Wingen :)

Discord bots are programs that allow automated interaction with Discord services.
They can be programmed to do simple tasks, such as play music or print a welcome message, or they can perform multiple tasks based on pre-programmed commands.
Discord bots are also handy for maintaining and moderating large servers as they can be used to moderate certain administration-level tasks.
There are also several bots available that you can access through the bot store.

In this tutorial, we’ll build a Discord bot using Python.

Table of Contents

1

Bot creation requirements

Creating a Discord bot is a simple, straightforward procedure and can be done through the developer portal or by using any code editor.
Before adding the code, a bot account needs to be created.
Go to the Discord developer portal at https://discord.com/developers/applications, log in, and click on ‘New Application’.
Name this application and click on the option bot from the list on the left side.
Now, add a bot and after naming it, copy the token for further use.

demo of how to grab a bot token

A Discord bot may need to access data that Discord qualifies as ‘sensitive’ in nature.
To give your bot access to privileged intents, you need to enable ‘Privileged Gateway Intents’ in the Developer Portal under the bots section.
This is only possible for unverified bots that are a part of fewer than 100 servers.
For verified bots, privileged intents need to be requested.

Enable Intents

Discord API

The Discord API allows for simpler and deeper integration with other services that enable users to have a smoother user experience.
The API is an open API that can be used to serve requests for bots and OAuth2 integration.
Various versions of the API are in use, you can use the preferred version by adding it to the request path such as https://discord.com/api/v{version_number}.
If the version is not mentioned then the default version is used to follow operations.

Create your first Python Discord bot

To start making a Discord bot in Python, the library we will use ‘discord.py’ which implements Discord’s API extensively. You will need the pip command to install discord.py.

pip install -U discord.py

We can now begin making the connection with the API.

import discord
TOKEN = "Insert Your Token here"
discord_client = discord.Client()
@discord_client.event
async def on_ready():
    print(f'{discord_client.user} Welcome to  Discord!')
discord_client.run(TOKEN)

This code is used to set up the initial connection with Discord. We first import the required library discord.
The token value can be obtained from the developer portal. You can place the token within the program in the placeholder string provided above.

For a more secure approach, you can place it in a .env file and refer to the same in your program.
Hard-coding secure keys in the program is not a very good developer practice. We are doing it here for demonstration purposes.
The discord_client object is an instance of the Client class, which is the connection to Discord.
@client.event is used to register an event, it is called when something happens i.e. some event is triggered.
The on_ready function will be called when the connection is set up and the bot is ready to take further steps.
The final step then runs the bot using the login token specified above.
Now run the code to see an established connection.

Output:

demonstration of a simple bot in Python

Welcome new members to the server

To print a welcome message when new users join the server, let’s add a new function on_member_join to the Python file.

import discord
from discord.ext import commands
TOKEN ="Insert Your token here"
intents=discord.Intents.all()
client = commands.Bot(command_prefix=',', intents=intents)
@client.event
async def on_member_join(member):
    await member.create_dm()
    await member.dm_channel.send(f'Hi {member.name}, welcome to the test Discord server!')
client.run(TOKEN)

Output:

demonstration of a welcome of new user by discord bot

The welcome_member function uses create.dm method to send the welcome message as a direct message to the user on joining.

Intents are permissions for the bot that are enabled based on the features necessary to run the bot. To run on_member_join we need to ensure intents are enabled.

Discord Bot Commands

Commands are short directions to perform a particular action or specific task.
Many Discord bots that are available in the bot store have multiple pre-configured commands that can be enabled or disabled by visiting the dashboard.
Besides the command, the prefix required to run the command in Discord will also be available. These prefixes can be of various types such as exclamation marks and many more.

Discord has various types of commands such as chat commands, text commands, and slash commands. The slash-type commands are always executed by using a slash as the prefix.

The text commands need to be entered in the text box based on the syntax of the command, whereas chat commands are used by directly entering the command in the text box.

import discord
import random
from discord.ext import commands
TOKEN ="Insert Your token here"
discord_bot = commands.Bot(command_prefix='!')
@discord_bot.command(name='morningquote')
async def msg(ctx):
    quotes = [
        "It's a new day",
        (
            "Be positive"
        ),
    ]
    response = random.choice(quotes)
    await ctx.send(response)
discord_bot.run(TOKEN)

While using commands, we use discord_bot.command to set the prefix for the command as ! and pass the name for the command as “morningquote”.
The command will be executed by the bot when a user types !morningquote in the chat.

Output:

example of a discord bot command

Send text, image, or file

To send any data using Python, we use the send() method.
To send a text, add content to the method as shown:

import discord
from discord.ext import commands
TOKEN = "Insert Your token here"
discord_bot = commands.Bot(command_prefix='!')
@discord_bot.command(name='senddata')
async def send_data(ctx):
    await ctx.send("hello there")
discord_bot.run(TOKEN)

Output:

demo of sending text with discord bot in python

To send an image, add the image file to the method as shown below. The file my_file.png will be sent when the command !sendimg is used in the chat.

import discord
from discord.ext import commands
import os
os.chdir("Your file path")
TOKEN = "Insert Your token here"
discord_bot = commands.Bot(command_prefix='!')
@discord_bot.command(name='senddata')
async def send_img(ctx):
	await ctx.send("image",file=discord.File('Your file name'))
discord_bot.run(TOKEN)

Output:

demo of sending image with discord bot in python

To send a file or file-like object, you need to first open the file with the open() method and then use the send method to send data.

Send colored text

In Discord, it is possible to send a text in 8 different colors by code markup. It uses Highlight.js and solarized dark theme to achieve this effect.

import discord
from discord.ext import commands
TOKEN = "Insert Your token here"
discord_bot = commands.Bot(command_prefix='!')
@discord_bot.command(name='coloured_text')
async def test(ctx): 
    retStr = str("""```yamlnThis is some colored Text```""") 
    await ctx.send(retStr)
discord_bot.run(TOKEN)

Output:

demo of sending text with discord bot in python

```yaml is the markup used to indicate the solarized cyan color. Below is a list of escape sequences or markup with their color codes that can be used to color your text.

Use the special characters such as ‘#’,'[‘, etc. wherever mentioned, to get the desired color. Note that the colored text is visible in the web application, but not the mobile application.

Default: #839496
```
Your text
```
Quote: #586e75
```bash
#Your text
```
Solarized Green: #859900
```diff
+ Your text
```
Solarized Cyan: #2aa198
```yaml
Your text
```
or
```cs
"Your text"
```
Solarized Blue: #268bd2
```ini
[Your text]
```
Solarized Yellow: #b58900
```fix
Your text
```
Solarized Orange: #cb4b16
```css
[Your text]
```
Solarized Red: #dc322f
```diff
-Your text
```

Simply replace the markup with markup for the desired color. The image below shows what the colors look like.
demonstrate how different colors are displayed

Get username from ID

To get the username based on the user id, we will use the fetch_user method. If the entire profile of a user is required then we can use the fetch_user_profile method.

import discord
from discord.ext import commands
TOKEN = "Insert Your token here"
discord_bot = commands.Bot(command_prefix='!')
@discord_bot.command(name='username')
async def user_name(ctx,user_id):
    user=await discord_bot.fetch_user(user_id)
    await ctx.send(user)
discord_bot.run(TOKEN)

Output:

demo of get username from user_id

Add user roles using the Discord bot

Roles are used to delegate permission to users within the server to help in management.
Roles can be implemented within large public servers such as in a learning-based server, roles like ‘student level 1’, ‘student level 2’, ‘teacher’, and ‘moderator’ can be assigned to users.
They can also be implemented in private servers with friends if such a need arises.

Each role has a different color and different permissions associated with it.
A user inherits the maximum permissions from each of the roles assigned to them.
The colors also work similarly, with the name of the member inheriting the role with the highest position in the hierarchy or with maximum permissions.
The roles have a linear hierarchy in Discord and can be managed from the ‘Manage role’ option in the ‘Roles’ tab.
Multiple roles with separate administrative powers can also be established so that the responsibilities of one user do not interfere with the other.

import discord
from discord import Member
from discord.ext.commands import has_permissions, MissingPermissions
from discord.ext import commands
TOKEN = "Insert Your token here"
intents=discord.Intents.all()
intents.members=True
bot = commands.Bot(command_prefix="!",intents=intents)
#code to add role
@bot.command()
@commands.has_permissions(manage_roles = True)
async def addRole(ctx, user : discord.Member, role:discord.Role):
    await user.add_roles(role)
    await ctx.send(f" Added {role} to {user.ention}")
@addRole.error
async def role_error(self,ctx,error):
    if isinstance(error, commands.MissingPermissions):
        await ctx.send("You are not authorized for this action")
bot.run(TOKEN)

To add a role, first, we use the commands to ensure that the user trying to add the role is authorized to do so.
We then use the add_roles method to add a function to the user.
Based on the requirements, you can allow multiple roles to be assigned to a user or use if-else statements to only allow one.
The role_error function is used to print an error message in case an unauthorized user tries to assign a role to another user.

Output:

demo of role assigning to users

User is assigned the ‘testoo’ role.

Send a Direct Message to Users

A lot of Discord servers are configured to send a welcome message via direct message when a user joins the server or to send a warning if they violate any of the server’s rules.
Let us look at a code that sends a DM when the designated command is used.

import discord
from discord.ext import commands
TOKEN ="Insert Your token here"
intents=discord.Intents.all()
client = commands.Bot(command_prefix='!', intents=intents)
@client.command()
async def drtmsg(ctx, user:discord.Member, *, message=None):
    message = "welcome"
    embed=discord.Embed(title=message)
    await user.send(embed=embed)
client.run(TOKEN)

This function will take input such as !drtmsg @User and then send the message “welcome” via private messaging to the selected user.

Output:

demonstration of sending DM to user with discord bot

Get members of a specific role and DM them

We first import the asyncio package for concurrent programming. We can use ctx.guild.roles to access the roles declared in the server.
The list of roles is fetched in user.roles which we can then traverse to find the correct role of the members and send them the desired message.

import asyncio 
import discord
from discord.ext import commands, tasks
Token ="Insert Your token here"
prefix="!"
intents=discord.Intents.all()
bot = commands.Bot(command_prefix=prefix,intents=intents)
@bot.command(name='dm') 
async def msg(ctx): 
    for guild in bot.guilds:  # all servers of the bot
        role = discord.utils.find(lambda r: r.name == 'Your role name', guild.roles)
        for member in guild.members:
            if role in member.roles:
                await member.send("Dm to role member")
bot.run(Token)

Output:

demo of members of role and send them a dm

Ban/Kick Members using Discord bot

To remove a member from the server you need to add the following code to your Python file.

import discord
from discord import Member
from discord.ext import commands
from discord.ext.commands import has_permissions, MissingPermissions
TOKEN = "Insert Your token here"
intents=discord.Intents.all()
discord_client = commands.Bot(command_prefix='!',intents=intents)
@discord_client.command()
@has_permissions(kick_members=True)
async def kick(ctx, member:discord.Member,*,reason=None):
    await member.kick(reason=reason)
    await ctx.send(f'The User {member} has been kicked from the server')
@kick.error
async def kick_error(ctx,error):
    if isinstance(error,commands.MissingPermissions):
        await ctx.send("You do not have required permission for the action performed")
discord_client.run(TOKEN)

First, import the member and required permissions method from the discord library to allow us to manage permissions and address a user.
We use @discord_client.command() to use the client object of the bot and inform it the code written ahead is a command.
@has_permissions is used to check whether the user performing the action is authorized to do so or not.
kick is the function that performs the actions of removing the given user from the server.

A dynamic reason can also be given, we have however simply stated the reason as “test”.
The second function kick_error is an exception function that is executed if the user is not authorized to kick another user out and the error message is printed.

A user that is kicked out is not permanently banned from the server.
To ensure that a user is added to the banned member list of the server add the function defined below.
This will ensure that the user cannot rejoin the server as long as they are present in the list.

import discord
from discord import Member
from discord.ext import commands
from discord.ext.commands import has_permissions, MissingPermissions
TOKEN = "Insert Your token here"
intents=discord.Intents.all()
discord_client = commands.Bot(command_prefix='!',intents=intents)
@discord_client.command()
@has_permissions(ban_members=True)
async def ban(ctx, member:discord.Member,*,reason=None):
    await member.ban(reason=reason)
    await ctx.send(f'The User {member} has been banned from the server')
@ban.error
async def ban_error(ctx,error):
    if isinstance(error,commands.MissingPermissions):
        await ctx.send("You do not have required permission for the action performed")
discord_client.run(TOKEN)

Output:

demo of ban user

Send a message at a specific time

To send a message at a specific time, the datetime library is required in addition to the discord library being used until now.

import discord
from datetime import datetime
client = discord.Client()
token = "Insert Your token here" 
channel_id=Insert Your channel id without quotes
def time_required():
    while True:
        current_time = datetime.now().strftime("%H:%M")
        if current_time == "Insert required time": 
            print("time reached")
            break
time_required()
@client.event
async def on_ready():
    print("bot:user ready == {0.user}".format(client))
    channel = client.get_channel(channel_id)
    await channel.send("timed message")
client.run(token)

The time_required function is created to establish when it is time to send the message. Until the required time is reached the bot will be in sleep mode.
Once it is time to send the message, the on_ready event will be executed, and the message “timed message” will be sent in the channel id mentioned in your code.

Output:

send message at time

Play audio files in Python

To play audio files in Python, the FFmpeg library is an appropriate choice.
It can be downloaded from https://ffmpeg.org/.
Hover over the Windows icon and select ‘Windows builds by BtbN’ or ‘Windows builds from gyan.dev’.
In case you have doubts about which library to choose, use the one by gyan.dev as it includes all the libraries that could be required.
The Download tab takes you to a link from where you can download the required zip file.

Extract the files and place them in the C drive in a new folder or any location of your choice from where they can go live.
Add the path of this folder to the ‘PATH’ environment variable.
Also, import the audio file to the directory in which the bot is, or you have to specify the full path to the audio file.
In the below code we set up the play command such that when the bot joins the voice channel it will play the audio file ‘venezuela.mp3’ using the FFmpeg library.

Install the ‘PyNaCl’ library using pip:

pip3 install pynacl

You have to install and place FFmpeg in your Environment variables for this to run successfully.

import discord
import nacl
from discord import FFmpegPCMAudio
from discord.ext import commands
intents=discord.Intents.all()
token="Insert Your token here"
discord_bot = commands.Bot(command_prefix='!',intents=intents)
@discord_bot.command(pass_context=True)
async def play(ctx):
    if(ctx.author.voice):
        channel = ctx.message.author.voice.channel
        voice=await channel.connect()
        music_source = FFmpegPCMAudio('venezuela.mp3')
        player = voice.play(music_source)
    else:
        await ctx.send("please join voice channel")
discord_bot.run(token)

Filter words

Sometimes users may use inappropriate language that the server moderators may want to delete to maintain the decorum of the server.
To avoid having to analyze every message one by one, a function can be written to automatically filter out and delete messages that contain a word from a pre-defined list of banned words.
Ensure that your bot has administration capabilities to run this code.

In the on_message function, if the message sent by the user contains a word from the list bannedWords, the message is deleted and a warning is sent to the user to refrain them from sending using such words again.
We then use process_commands to ensure the bot continues to process other commands assigned to it.

import discord
from discord.ext import commands, tasks
import re
Token ="Insert Your token here"
prefix="!"
bot = commands.Bot(command_prefix=prefix)
def msg_contains_word(msg, word):
    return re.search(fr'b({word})b', msg) is not None
@bot.command()
async def loadcog(ctx, cog):
    bot.load_extension(f"cogs.{cog}")
@bot.command()
async def unloadcog(ctx, cog):
    bot.unload_extension(f"cogs.{cog}")
bannedWords={"ret"}
@bot.event
async def on_message(message):
    messageAuthor = message.author
    if bannedWords != None and (isinstance(message.channel, discord.channel.DMChannel) == False):
        for bannedWord in bannedWords:
            if msg_contains_word(message.content.lower(), bannedWord):
                await message.delete()
                await message.channel.send(f"{messageAuthor.mention} Message contains  a banned word.")
    await bot.process_commands(message)
bot.run(Token)

Output:

demo of filter words

Conclusion

Discord is a powerful social media tool with a wide array of features. Bots additionally are extremely versatile and are capable to do a lot of things, some of which have been covered in this tutorial.
We can enable our bot to do a lot more things with the use of the correct combination of commands and events.

Mokhtar Ebrahim

Mokhtar is the founder of LikeGeeks.com. He works as a Linux system administrator since 2010. He is responsible for maintaining, securing, and troubleshooting Linux servers for multiple clients around the world. He loves writing shell and Python scripts to automate his work.

Время на прочтение
5 мин

Количество просмотров 17K

Началось все с того, что мне захотелось написать музыкального бота для своего discord сервера.

При проектировании проекта, я решил разделить его на две части. Первая — получение музыки из ВК. Вторая — сам бот. И начать я решил с первой части.

Поиск какой-либо информации на этот счет или уже возможно готового куска кода не принес никаких результатов из-за чего очевидным решением данной проблемы было то, что придется разбираться с этим самому.

Я решил посмотреть что сейчас отдает ВКонтакте при воспроизведении записи и полез во вкладку network, вот что я там увидел:

Фото

Теперь передо мной стояла новая задача, как получить с определенного аудио нужную ссылку на m3u8 файл и уже потом думать как его разбирать и собирать в дальнейшем в цельным mp3 файл.

В ходе раздумий был найден довольно простой вариант в виде библиотеки для питона vk_api и реализация получения такой ссылки через эту библиотеку выглядит так:

from vk_api import VkApi
from vk_api.audio import VkAudio

login = "+7XXXXXXXXXX"
password = "your_password"

vk_session = VKApi(
  login=login,
  password=password,
  api_version='5.81'
)
vk_session.auth()

vk_audio = VKAudio(vk_session)

# Делаем поиск аудио по названию
# Так же можно получать аудио со страницы функцией .get_iter(owner_id)
# где owner_id это айди страницы
# или же можно получить аудио с альбома, где мы сначала получаем айди альбомов
# функцией .get_albums_iter()
# и после снова вызываем .get_iter(owner_id, album_id), где album_id полученный
# айди альбома
q = "audio name"
audio = next(vk_audio.search_iter(q=q))
url = audio['url'] # получаем ту длиннющую ссылку на m3u8 файл

Вот мы и получили ссылку на этот файл и встал вопрос, а что делать дальше. Я попробовал запихнуть эту ссылку в ffmpeg и уже было обрадовался, ведь он скачал мой заветный аудиофайл и сразу же сделал конвертацию в mp3, однако, счастье мое длилось не долго, ведь ffmpeg хоть и скачал все сегменты, самостоятельно склеив их, но зашифрованные сегменты он не расшифровал, поэтому давайте еще раз взглянем на внутренности m3u8 файла

#EXTM3U
#EXT-X-TARGETDURATION:25
#EXT-X-ALLOW-CACHE:YES
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-KEY:METHOD=AES-128,URI="https://cs1-66v4.vkuseraudio.net/s/v1/ac/wYaompMqHNQpBIH183wK68QVW45tvaJLaznkPiqES66JM-xzffiiM4KQx5WPS0Vg99U9ggCDronPKO8bzit3v_j8fH6LymN2pngBXYTv5uaDnFiAfc2aXv848bhRJEyFVB1gaJw1VR4BS9WnSb8jIMd0haPgfvJMcWC7FW7wpFkGU14/key.pub"
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:2.000,
seg-1-a1.ts
#EXT-X-KEY:METHOD=NONE
#EXTINF:4.000,
seg-2-a1.ts
#EXTINF:20.000,
seg-3-a1.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://cs1-66v4.vkuseraudio.net/s/v1/ac/wYaompMqHNQpBIH183wK68QVW45tvaJLaznkPiqES66JM-xzffiiM4KQx5WPS0Vg99U9ggCDronPKO8bzit3v_j8fH6LymN2pngBXYTv5uaDnFiAfc2aXv848bhRJEyFVB1gaJw1VR4BS9WnSb8jIMd0haPgfvJMcWC7FW7wpFkGU14/key.pub"
#EXTINF:20.000,
seg-4-a1.ts
#EXT-X-KEY:METHOD=NONE
#EXTINF:25.444,
seg-5-a1.ts
#EXT-X-ENDLIST

Мы видим, что перед зашифрованными сегментами в EXT-X-KEY указан метод шифровки AES-128 и ссылка на скачку ключа для расшифровки.

Для решения уже этой проблемы была найдена прекрасная библиотека m3u8 и pycryptodome:

import m3u8
import requests
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

# Получаем этот самый m3u8 файл
m3u8_data = m3u8.load(
  url="" # Вставляем наш полученный ранее url
)
segments = m3u8.data.get("segments")

# Парсим файл в более удобный формат
segments_data = {}

for segment in segments:
  segment_uri = segment.get("uri")  
  extended_segment = {
    "segment_method": None,
    "method_uri": None
  }
  if segment.get("key").get("method") == "AES-128":
    extended_segment["segment_method"] = True
    extended_segment["method_uri"] = segment.get("key").get("uri")
    
	segments_data[segment_uri] = extended_segment
  
# И наконец качаем все сегменты с расшифровкой
uris = segments_data.keys()

downloaded_segments = []
for uri in uris:
  # Используем начальный url где мы подменяем index.m3u8 на наш сегмент
  audio = requests.get(url=index_url.replace("index.m3u8", uri))
  # Сохраняем .ts файл
  downloaded_segments.append(audio.content)
  # Если у сегмента есть метод, то расшифровываем его
  if segments_data.get(uri).get("segment_method") is not None:
    # Качаем ключ
    key_uri = segments_data.get(uri).get("method_uri")
    key = requests.get(url=key_uri)
    
    iv = downloaded_segments[-1][0:16]
    ciphered_data = downloaded_segments[-1][16:]
    
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    data = unpad(cipher.decrypt(ciphered_data), AES.block_size)
    downloaded_segments[-1] = data
    
    
complete_segments = b''.join(downloaded_segments)
  

И наконец конвертируем все в mp3 формат, для чего нам понадобится установленный ffmpeg на ПК.

import os

with open('../m3u8_downloader/segments/temp.ts', 'w+b') as f:
  f.write(complete_segments)

os.system(f'ffmpeg -i "media/music/segments/temp.ts" -vcodec copy '
          f'-acodec copy -vbsf h264_mp4toannexb "media/music/mp3/temp.wav"')
os.remove("../m3u8_downloader/segments/temp.ts")

Для меня это был довольно интересный опыт, поскольку я никогда до этого в своей жизни не работал с зашифрованными файлами и HLS протоколом, надеюсь Вам тоже было интересно читать это. Так же надеюсь я смог помочь другим людям, ведь никаких решений по скачиванию аудио с ВКонтакте на питоне в 2022 году я не нашел.

Так же выложу весь код:

Hidden text

import os
import m3u8
import requests
from vk_api import VkApi
from vk_api.audio import VkAudio
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad


class M3U8Downloader:

    def __init__(self, login: str, password: str):

        self._vk_session = VkApi(
            login=login,
            password=password,
            api_version='5.81'
        )
        self._vk_session.auth()

        self._vk_audio = VkAudio(self._vk_session)

    def download_audio(self, q: str):
        url = self._get_audio_url(q=q)
        segments = self._get_audio_segments(url=url)
        segments_data = self._parse_segments(segments=segments)
        segments = self._download_segments(segments_data=segments_data, index_url=url)
        self._convert_ts_to_mp3(segments=segments)

    @staticmethod
    def _convert_ts_to_mp3(segments: bytes):
        with open(f'media/music/segments/temp.ts', 'w+b') as f:
        		f.write(segments)
        os.system(f'ffmpeg -i "media/music/segments/temp.ts" -vcodec copy '
                  f'-acodec copy -vbsf h264_mp4toannexb "media/music/mp3/temp.wav"')
        os.remove("../m3u8_downloader/segments/temp.ts")

    def _get_audio_url(self, q: str):
        self._vk_audio.get_albums_iter()
        audio = next(self._vk_audio.search_iter(q=q))
        url = audio['url']
        return url

    @staticmethod
    def _get_audio_segments(url: str):
        m3u8_data = m3u8.load(
            uri=url
        )
        return m3u8_data.data.get("segments")

    @staticmethod
    def _parse_segments(segments: list):
        segments_data = {}

        for segment in segments:
            segment_uri = segment.get("uri")

            extended_segment = {
                "segment_method": None,
                "method_uri": None
            }
            if segment.get("key").get("method") == "AES-128":
                extended_segment["segment_method"] = True
                extended_segment["method_uri"] = segment.get("key").get("uri")
            segments_data[segment_uri] = extended_segment
        return segments_data

    @staticmethod
    def _download_segments(segments_data: dict, index_url: str) -> bin:
    downloaded_segments = []

    for uri in segments_data.keys():
        audio = requests.get(url=index_url.replace("index.m3u8", uri))

        downloaded_segments.append(audio.content)

        if segments_data.get(uri).get("segment_method") is not None:
            key_uri = segments_data.get(uri).get("method_uri")
            key = download_key(key_uri=key_uri)

            iv = downloaded_segments[-1][0:16]
            ciphered_data = downloaded_segments[-1][16:]

            cipher = AES.new(key, AES.MODE_CBC, iv=iv)
            data = unpad(cipher.decrypt(ciphered_data), AES.block_size)
            downloaded_segments[-1] = data

    return b''.join(downloaded_segments) 

    @staticmethod
    def download_key(key_uri: str) -> bin:
    return requests.get(url=key_uri).content
       
      
login = "" # phone
password = "" # password
md = M3U8Downloader(login=login, password=password)

q = "Воллны Волны" # Запрос музыки по названию
md.download_audio()

RhinoBot: The music bot for Discord.

MusicBot is a Discord music bot written in Python. It plays requested songs and if the queue becomes empty it will play through a list of existing songs.

How do I set it up?

CLICK HERE to find the guide that suites your operating system.

Commands

Commands are listed here.

Configuration

The main configuration file is config/options.ini, but is not included. Simply make a copy of example_options.ini and rename to options.ini. See example_options.ini for more information on how to configure it.

CLICK HERE for more details.

Great, now how do I use it?

Download the bot, set the dependencies up, then run runbot.bat! (or run.sh on mac/linux) Read the tutorial if you don’t know what to do.

If you have any errors, read the FAQ. If that didn’t help, you can ask for assistance on the discord help server. Is is recommended to take screenshots so the developers can see errors.

Rhino Help Server

FAQ

Some frequently asked questions are listed on the wiki here.

Понравилась статья? Поделить с друзьями:
  • Как написать бота для вк на python для беседы
  • Как написать бота для вк на php
  • Как написать бота для ватсап
  • Как написать бота для вайбер
  • Как написать бота для браузера