aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2016-01-31 22:00:14 -0500
committerRapptz <[email protected]>2016-01-31 22:06:12 -0500
commit1cd3c0b5cb9c1ae423c771cc1ffceb73d08b6158 (patch)
tree7f653d9fbc9cd908508e368a8911ca56542ce21e
parentChange options in VoiceClient.create_ytdl_player to ytdl_options. (diff)
downloaddiscord.py-1cd3c0b5cb9c1ae423c771cc1ffceb73d08b6158.tar.xz
discord.py-1cd3c0b5cb9c1ae423c771cc1ffceb73d08b6158.zip
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.
-rw-r--r--discord/voice_client.py88
1 files changed, 78 insertions, 10 deletions
diff --git a/discord/voice_client.py b/discord/voice_client.py
index c7d108e1..5b129e70 100644
--- a/discord/voice_client.py
+++ b/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.