@ -91,7 +91,7 @@ class YoutubeDL(object):
downloadarchive : File name of a file where all downloads are recorded .
Videos already present in the file are not downloaded
again .
The following parameters are not used by YoutubeDL itself , they are used by
the FileDownloader :
nopart , updatetime , buffersize , ratelimit , min_filesize , max_filesize , test ,
@ -216,10 +216,10 @@ class YoutubeDL(object):
If stderr is a tty file the ' WARNING: ' will be colored
'''
if sys . stderr . isatty ( ) and os . name != ' nt ' :
_msg_header = u ' \033 [0;33mWARNING: \033 [0m '
_msg_header = u ' \033 [0;33mWARNING: \033 [0m '
else :
_msg_header = u ' WARNING: '
warning_message = u ' %s %s ' % ( _msg_header , message )
_msg_header = u ' WARNING: '
warning_message = u ' %s %s ' % ( _msg_header , message )
self . to_stderr ( warning_message )
def report_error ( self , message , tb = None ) :
@ -234,19 +234,6 @@ class YoutubeDL(object):
error_message = u ' %s %s ' % ( _msg_header , message )
self . trouble ( error_message , tb )
def slow_down ( self , start_time , byte_counter ) :
""" Sleep if the download speed is over the rate limit. """
rate_limit = self . params . get ( ' ratelimit ' , None )
if rate_limit is None or byte_counter == 0 :
return
now = time . time ( )
elapsed = now - start_time
if elapsed < = 0.0 :
return
speed = float ( byte_counter ) / elapsed
if speed > rate_limit :
time . sleep ( ( byte_counter - rate_limit * ( now - start_time ) ) / rate_limit )
def report_writedescription ( self , descfn ) :
""" Report that the description file is being written """
self . to_screen ( u ' [info] Writing video description to: ' + descfn )
@ -330,14 +317,14 @@ class YoutubeDL(object):
return ( u ' %(title)s has already been recorded in archive '
% info_dict )
return None
def extract_info ( self , url , download = True , ie_key = None , extra_info = { } ) :
'''
Returns a list with a dictionary for each video we find .
If ' download ' , also downloads the videos .
extra_info is a dict containing the extra values to add to each result
'''
if ie_key :
ies = [ self . get_info_extractor ( ie_key ) ]
else :
@ -379,7 +366,7 @@ class YoutubeDL(object):
raise
else :
self . report_error ( u ' no suitable InfoExtractor: %s ' % url )
def process_ie_result ( self , ie_result , download = True , extra_info = { } ) :
"""
Take the result of the ie ( may be modified ) and resolve all unresolved
@ -403,7 +390,7 @@ class YoutubeDL(object):
elif result_type == ' playlist ' :
# We process each entry in the playlist
playlist = ie_result . get ( ' title ' , None ) or ie_result . get ( ' id ' , None )
self . to_screen ( u ' [download] Downloading playlist: %s ' % playlist )
self . to_screen ( u ' [download] Downloading playlist: %s ' % playlist )
playlist_results = [ ]
@ -421,12 +408,12 @@ class YoutubeDL(object):
self . to_screen ( u " [ %s ] playlist ' %s ' : Collected %d video ids (downloading %d of them) " %
( ie_result [ ' extractor ' ] , playlist , n_all_entries , n_entries ) )
for i , entry in enumerate ( entries , 1 ) :
self . to_screen ( u ' [download] Downloading video # %s of %s ' % ( i , n_entries ) )
for i , entry in enumerate ( entries , 1 ) :
self . to_screen ( u ' [download] Downloading video # %s of %s ' % ( i , n_entries ) )
extra = {
' playlist ' : playlist ,
' playlist_index ' : i + playliststart ,
}
' playlist ' : playlist ,
' playlist_index ' : i + playliststart ,
}
if not ' extractor ' in entry :
# We set the extractor, if it's an url it will be set then to
# the new extractor, but if it's already a video we must make
@ -450,6 +437,22 @@ class YoutubeDL(object):
else :
raise Exception ( ' Invalid result type: %s ' % result_type )
def select_format ( self , format_spec , available_formats ) :
if format_spec == ' best ' or format_spec is None :
return available_formats [ - 1 ]
elif format_spec == ' worst ' :
return available_formats [ 0 ]
else :
extensions = [ u ' mp4 ' , u ' flv ' , u ' webm ' , u ' 3gp ' ]
if format_spec in extensions :
filter_f = lambda f : f [ ' ext ' ] == format_spec
else :
filter_f = lambda f : f [ ' format_id ' ] == format_spec
matches = list ( filter ( filter_f , available_formats ) )
if matches :
return matches [ - 1 ]
return None
def process_video_result ( self , info_dict , download = True ) :
assert info_dict . get ( ' _type ' , ' video ' ) == ' video '
@ -460,7 +463,8 @@ class YoutubeDL(object):
# This extractors handle format selection themselves
if info_dict [ ' extractor ' ] in [ u ' youtube ' , u ' Youku ' , u ' YouPorn ' , u ' mixcloud ' ] :
self . process_info ( info_dict )
if download :
self . process_info ( info_dict )
return info_dict
# We now pick which formats have to be downloaded
@ -472,17 +476,14 @@ class YoutubeDL(object):
# We check that all the formats have the format and format_id fields
for ( i , format ) in enumerate ( formats ) :
if format . get ( ' format ' ) is None :
if format . get ( ' height ' ) is not None :
if format . get ( ' width ' ) is not None :
format_desc = u ' %s x %s ' % ( format [ ' width ' ] , format [ ' height ' ] )
else :
format_desc = u ' %s p ' % format [ ' height ' ]
else :
format_desc = ' ??? '
format [ ' format ' ] = format_desc
if format . get ( ' format_id ' ) is None :
format [ ' format_id ' ] = compat_str ( i )
if format . get ( ' format ' ) is None :
format [ ' format ' ] = u ' {id} - {res}{note} ' . format (
id = format [ ' format_id ' ] ,
res = self . format_resolution ( format ) ,
note = u ' ({}) ' . format ( format [ ' format_note ' ] ) if format . get ( ' format_note ' ) is not None else ' ' ,
)
if self . params . get ( ' listformats ' , None ) :
self . list_formats ( info_dict )
@ -504,22 +505,20 @@ class YoutubeDL(object):
formats = sorted ( formats , key = _free_formats_key )
req_format = self . params . get ( ' format ' , ' best ' )
if req_format is None :
req_format = ' best '
formats_to_download = [ ]
if req_format == ' best ' or req_format is None :
formats_to_download = [ formats [ - 1 ] ]
elif req_format == ' worst ' :
formats_to_download = [ formats [ 0 ] ]
# The -1 is for supporting YoutubeIE
el if req_format in ( ' -1 ' , ' all ' ) :
if req_format in ( ' -1 ' , ' all ' ) :
formats_to_download = formats
else :
# We can accept formats requestd in the format: 34/10/ 5, we pick
# We can accept formats requestd in the format: 34/5/best , we pick
# the first that is available, starting from left
req_formats = req_format . split ( ' / ' )
for rf in req_formats :
matches = filter ( lambda f : f [ ' format_id ' ] == rf , formats )
if matches :
formats_to_download = [ matches [ 0 ] ]
selected_format = self . select_format ( rf , formats )
if selected_format is not None :
formats_to_download = [ selected_format ]
break
if not formats_to_download :
raise ExtractorError ( u ' requested format not available ' )
@ -610,20 +609,20 @@ class YoutubeDL(object):
if self . params . get ( ' writeannotations ' , False ) :
try :
annofn = filename + u ' .annotations.xml '
self . report_writeannotations ( annofn )
with io . open ( encodeFilename ( annofn ) , ' w ' , encoding = ' utf-8 ' ) as annofile :
annofile . write ( info_dict [ ' annotations ' ] )
annofn = filename + u ' .annotations.xml '
self . report_writeannotations ( annofn )
with io . open ( encodeFilename ( annofn ) , ' w ' , encoding = ' utf-8 ' ) as annofile :
annofile . write ( info_dict [ ' annotations ' ] )
except ( KeyError , TypeError ) :
self . report_warning ( u ' There are no annotations to write. ' )
except ( OSError , IOError ) :
self . report_error ( u ' Cannot write annotations file: ' + annofn )
return
self . report_error ( u ' Cannot write annotations file: ' + annofn )
return
subtitles_are_requested = any ( [ self . params . get ( ' writesubtitles ' , False ) ,
self . params . get ( ' writeautomaticsub ' ) ] )
if subtitles_are_requested and ' subtitles ' in info_dict and info_dict [ ' subtitles ' ] :
if subtitles_are_requested and ' subtitles ' in info_dict and info_dict [ ' subtitles ' ] :
# subtitles download errors are already managed as troubles in relevant IE
# that way it will silently go on when used with unsupporting IE
subtitles = info_dict [ ' subtitles ' ]
@ -645,7 +644,7 @@ class YoutubeDL(object):
infofn = filename + u ' .info.json '
self . report_writeinfojson ( infofn )
try :
json_info_dict = dict ( ( k , v ) for k , v in info_dict . items ( ) if not k in [ ' urlhandle ' ] )
json_info_dict = dict ( ( k , v ) for k , v in info_dict . items ( ) if not k in [ ' urlhandle ' ] )
write_json_file ( json_info_dict , encodeFilename ( infofn ) )
except ( OSError , IOError ) :
self . report_error ( u ' Cannot write metadata to JSON file ' + infofn )
@ -715,7 +714,7 @@ class YoutubeDL(object):
keep_video = None
for pp in self . _pps :
try :
keep_video_wish , new_info = pp . run ( info )
keep_video_wish , new_info = pp . run ( info )
if keep_video_wish is not None :
if keep_video_wish :
keep_video = keep_video_wish
@ -754,16 +753,31 @@ class YoutubeDL(object):
with locked_file ( fn , ' a ' , encoding = ' utf-8 ' ) as archive_file :
archive_file . write ( vid_id + u ' \n ' )
@staticmethod
def format_resolution ( format ) :
if format . get ( ' height ' ) is not None :
if format . get ( ' width ' ) is not None :
res = u ' %s x %s ' % ( format [ ' width ' ] , format [ ' height ' ] )
else :
res = u ' %s p ' % format [ ' height ' ]
else :
res = ' ??? '
return res
def list_formats ( self , info_dict ) :
formats_s = [ ]
for format in info_dict . get ( ' formats ' , [ info_dict ] ) :
formats_s . append ( " %s \t : \t %s \t [ %s ] " % ( format [ ' format_id ' ] ,
format [ ' ext ' ] ,
format . get ( ' format ' , ' ??? ' ) ,
)
)
formats_s . append ( u ' %-15s : %-5s %-15s [ %s ] ' % (
format [ ' format_id ' ] ,
format [ ' ext ' ] ,
format . get ( ' format_note ' ) or ' - ' ,
self . format_resolution ( format ) ,
)
)
if len ( formats_s ) != 1 :
formats_s [ 0 ] + = ' (worst) '
formats_s [ 0 ] + = ' (worst) '
formats_s [ - 1 ] + = ' (best) '
formats_s = " \n " . join ( formats_s )
self . to_screen ( u " [info] Available formats for %s : \n format code \t extension \n %s " % ( info_dict [ ' id ' ] , formats_s ) )
self . to_screen ( u ' [info] Available formats for %s : \n '
u ' format code extension note resolution \n %s ' % (
info_dict [ ' id ' ] , formats_s ) )