Reputation: 852
I want to make my bot playing audio from an url, but I don't want to download the file ...
Here is my code:
@commands.command(name='test')
async def test(self, ctx):
search = "morpheus tutorials discord bot python"
if ctx.message.author.voice == None:
await ctx.send(embed=Embeds.txt("No Voice Channel", "You need to be in a voice channel to use this command!", ctx.author))
return
channel = ctx.message.author.voice.channel
voice = discord.utils.get(ctx.guild.voice_channels, name=channel.name)
voice_client = discord.utils.get(self.client.voice_clients, guild=ctx.guild)
if voice_client == None:
await voice.connect()
else:
await voice_client.move_to(channel)
search = search.replace(" ", "+")
html = urllib.request.urlopen("https://www.youtube.com/results?search_query=" + search)
video_ids = re.findall(r"watch\?v=(\S{11})", html.read().decode())
#################################
await ctx.send("https://www.youtube.com/watch?v=" + video_ids[0])
# AND HERE SHOULD IT PLAY
#################################
I have tryied create_ytdl_player method, but saw that its no longer supported what can I do?
Upvotes: 4
Views: 13893
Reputation: 41
If the source
argument is a str
it is directly fed as input to ffmpeg
binary by FFmpegPCMAudio
internally.
ffmpeg
supports urls as input out of the box. so you can just pass the url instead of file path.
source = FFmpegPCMAudio("https://example.com/demo.mp3", executable="ffmpeg")
ctx.voice_client.play(source, after=None)
Upvotes: 1
Reputation: 66
use pafy.
First import some stuff and set FFmpeg options...
import pafy
from discord import FFmpegPCMAudio, PCMVolumeTransformer
FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5','options': '-vn'}
Then play it
@commands.command(name='test')
async def test(self, ctx):
search = "morpheus tutorials discord bot python"
if ctx.message.author.voice == None:
await ctx.send(embed=Embeds.txt("No Voice Channel", "You need to be in a voice channel to use this command!", ctx.author))
return
channel = ctx.message.author.voice.channel
voice = discord.utils.get(ctx.guild.voice_channels, name=channel.name)
voice_client = discord.utils.get(self.client.voice_clients, guild=ctx.guild)
if voice_client == None:
voice_client = await voice.connect()
else:
await voice_client.move_to(channel)
search = search.replace(" ", "+")
html = urllib.request.urlopen("https://www.youtube.com/results?search_query=" + search)
video_ids = re.findall(r"watch\?v=(\S{11})", html.read().decode())
await ctx.send("https://www.youtube.com/watch?v=" + video_ids[0])
song = pafy.new(video_ids[0]) # creates a new pafy object
audio = song.getbestaudio() # gets an audio source
source = FFmpegPCMAudio(audio.url, **FFMPEG_OPTIONS) # converts the youtube audio source into a source discord can use
voice_client.play(source) # play the source
Upvotes: 3
Reputation: 1639
Replace the bot
with client
if you need to. Then, try this out:
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(description="joins a voice channel")
async def join(self, 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
@commands.command(description="streams music")
async def play(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('Player error: %s' % e) if e else None)
await ctx.send('Now playing: {}'.format(player.title))
@commands.command(description="stops and disconnects the bot from voice")
async def leave(self, ctx):
await ctx.voice_client.disconnect()
@play.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()
def setup(bot):
bot.add_cog(Music(bot))
Not only will this play from URL, but it will also play from the name of the video itself.
Upvotes: 0