'I can't play song with Youtube URL on my Discord Bot
So I trying to create my own music bot for my own server with Python since Rhythm and Groovy unavailable, but I can't play it with YouTube URL. Do anyone have the solution?
@commands.command()
async def play(self,ctx,*,url):
ctx.voice_client.stop()
FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
YDL_OPTIONS = {'format':"bestaudio"}
vc = ctx.voice_client
with youtube_dl.YoutubeDL(YDL_OPTIONS) as ydl:
info = ydl.extract_info(url, download=False)
if 'entries' in info:
url2 = info["entries"][0]["formats"][0]['url']
elif 'formats' in info:
url2 = info["entries"][0]["formats"][0]['url']
source = await discord.FFmpegOpusAudio.from_probe(url2, **FFMPEG_OPTIONS)
vc.play(source)
Solution 1:[1]
import asyncio
import os
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=1.0):
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)
bot = commands.Bot(command_prefix = '!')
@bot.event
async def on_ready():
await bot.change_presence(activity = discord.Activity(type =
discord.ActivityType.listening, name = "your favourite song :)"), status =
discord.Status.idle)
print('bot ready')
@bot.command(description="joins a voice channel")
async def join(ctx):
if ctx.author.voice is None or ctx.author.voice.channel is None:
return await ctx.send('You need to be in a voice channel to use this
command!')
voice_channel = ctx.author.voice.channel
if ctx.voice_client is None:
vc = await voice_channel.connect()
else:
await ctx.voice_client.move_to(voice_channel)
vc = ctx.voice_client
async def on_ready(self):
for guild in self.client.guilds:
self.song_queue[guild.id] = []
async def check_queue(ctx):
if len(ctx.song_queue[ctx.guild.id]) > 0:
ctx.voice_client.stop()
await ctx.play(ctx.song_queue[ctx.guild.id][0])
@bot.command(description="streams music", aliases = ['pl','p'])
async def play(ctx,*, url):
async with ctx.typing():
player = await YTDLSource.from_url(url, loop= 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))
song_queue = check_queue(ctx)
song_queue[ctx.guild.id].append(player)
@bot.command(description="stops and disconnects the bot from voice")
async def leave(ctx):
await ctx.voice_client.disconnect()
@play.before_invoke
async def ensure_voice(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.run('TOKEN')
Try this code; works only with url. Also, I have only the join, play and leave command, it's just a very basic music bot, and it does not queue either.
Solution 2:[2]
@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.
"""
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)))
The above code has been taken from here. As this is a common question I thought that using pre-tested code would be the correct option.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | xeno |
| Solution 2 |
