@ -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.