aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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.