Browse Source

Make VoiceClient.create_ytdl_player a coroutine.

This is a breaking change. The reason to make it a coroutine is so that
the info retrieval is not blocking since there are rare instances where
it would take an abnormally long time. The player returned is also
augmented to have more attributes relating to the stream itself.
pull/105/head
Rapptz 9 years ago
parent
commit
1cd3c0b5cb
  1. 88
      discord/voice_client.py

88
discord/voice_client.py

@ -48,6 +48,8 @@ import struct
import threading
import subprocess
import shlex
import functools
import datetime
log = logging.getLogger(__name__)
@ -124,7 +126,6 @@ class ProcessPlayer(StreamPlayer):
self.process.kill()
super().stop()
class VoiceClient:
"""Represents a Discord voice connection.
@ -416,8 +417,11 @@ class VoiceClient:
raise ClientException('Popen failed: {0.__name__} {1}'.format(type(e), str(e))) from e
@asyncio.coroutine
def create_ytdl_player(self, url, *, ytdl_options=None, **kwargs):
"""Creates a stream player for youtube or other services that launches
"""|coro|
Creates a stream player for youtube or other services that launches
in a separate thread to play the audio.
The player uses the ``youtube_dl`` python library to get the information
@ -429,7 +433,38 @@ class VoiceClient:
variable in order for this to work.
The operations that can be done on the player are the same as those in
:meth:`create_stream_player`.
:meth:`create_stream_player`. The player has been augmented and enhanced
to have some info extracted from the URL. If youtube-dl fails to extract
the information then the attribute is ``None``. The ``yt``, ``url``, and
``download_url`` attributes are always available.
+---------------------+---------------------------------------------------------+
| Operation | Description |
+=====================+=========================================================+
| player.yt | The `YoutubeDL <ytdl>` instance. |
+---------------------+---------------------------------------------------------+
| player.url | The URL that is currently playing. |
+---------------------+---------------------------------------------------------+
| player.download_url | The URL that is currently being downloaded to ffmpeg. |
+---------------------+---------------------------------------------------------+
| player.title | The title of the audio stream. |
+---------------------+---------------------------------------------------------+
| player.description | The description of the audio stream. |
+---------------------+---------------------------------------------------------+
| player.uploader | The uploader of the audio stream. |
+---------------------+---------------------------------------------------------+
| player.upload_date | A datetime.date object of when the stream was uploaded. |
+---------------------+---------------------------------------------------------+
| player.duration | The duration of the audio in seconds. |
+---------------------+---------------------------------------------------------+
| player.likes | How many likes the audio stream has. |
+---------------------+---------------------------------------------------------+
| player.dislikes | How many dislikes the audio stream has. |
+---------------------+---------------------------------------------------------+
| player.is_live | Checks if the audio stream is currently livestreaming. |
+---------------------+---------------------------------------------------------+
| player.views | How many views the audio stream has. |
+---------------------+---------------------------------------------------------+
.. _ytdl: https://github.com/rg3/youtube-dl/blob/master/youtube_dl/YoutubeDL.py#L117-L265
@ -438,8 +473,8 @@ class VoiceClient:
Basic usage: ::
voice = yield from client.join_voice_channel(channel)
player = voice.create_ytdl_player('https://www.youtube.com/watch?v=d62TYemN6MQ')
voice = await client.join_voice_channel(channel)
player = await voice.create_ytdl_player('https://www.youtube.com/watch?v=d62TYemN6MQ')
player.start()
Parameters
@ -462,14 +497,14 @@ class VoiceClient:
Returns
--------
StreamPlayer
A stream player with specific operations.
See :meth:`create_stream_player`.
An augmented StreamPlayer that uses ffmpeg.
See :meth:`create_stream_player` for base operations.
"""
import youtube_dl
use_avconv = kwargs.get('use_avconv', False)
opts = {
'format': 'webm[abr>0]' if 'youtube' in url else 'best',
'format': 'webm[abr>0]/bestaudio/best',
'prefer_ffmpeg': not use_avconv
}
@ -477,9 +512,42 @@ class VoiceClient:
opts.update(ytdl_options)
ydl = youtube_dl.YoutubeDL(opts)
info = ydl.extract_info(url, download=False)
func = functools.partial(ydl.extract_info, url, download=False)
info = yield from self.loop.run_in_executor(None, func)
log.info('playing URL {}'.format(url))
return self.create_ffmpeg_player(info['url'], **kwargs)
download_url = info['url']
player = self.create_ffmpeg_player(download_url, **kwargs)
# set the dynamic attributes from the info extraction
player.download_url = download_url
player.url = url
player.yt = ydl
player.views = info.get('view_count')
player.is_live = bool(info.get('is_live'))
player.likes = info.get('like_count')
player.dislikes = info.get('dislike_count')
player.duration = info.get('duration')
player.uploader = info.get('uploader')
is_twitch = 'twitch' in url
if is_twitch:
# twitch has 'title' and 'description' sort of mixed up.
player.title = info.get('description')
player.description = None
else:
player.title = info.get('title')
player.description = info.get('description')
# upload date handling
date = info.get('upload_date')
if date:
try:
date = datetime.datetime.strptime(date, '%Y%M%d').date()
except ValueError:
date = None
player.upload_date = date
return player
def encoder_options(self, *, sample_rate, channels=2):
"""Sets the encoder options for the OpusEncoder.

Loading…
Cancel
Save