Do not warn about fixed output template if --max-downloads is 1
[youtube-dl] / youtube_dl / __init__.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 __authors__  = (
5     'Ricardo Garcia Gonzalez',
6     'Danny Colligan',
7     'Benjamin Johnson',
8     'Vasyl\' Vavrychuk',
9     'Witold Baryluk',
10     'Paweł Paprota',
11     'Gergely Imreh',
12     'Rogério Brito',
13     'Philipp Hagemeister',
14     'Sören Schulze',
15     'Kevin Ngo',
16     'Ori Avtalion',
17     'shizeeg',
18     'Filippo Valsorda',
19     'Christian Albrecht',
20     'Dave Vasilevsky',
21     'Jaime Marquínez Ferrándiz',
22     'Jeff Crouse',
23     'Osama Khalid',
24     'Michael Walter',
25     'M. Yasoob Ullah Khalid',
26     'Julien Fraichard',
27     'Johny Mo Swag',
28     'Axel Noack',
29     'Albert Kim',
30     'Pierre Rudloff',
31     'Huarong Huo',
32     'Ismael Mejía',
33     'Steffan \'Ruirize\' James',
34     'Andras Elso',
35     'Jelle van der Waa',
36     'Marcin Cieślak',
37     'Anton Larionov',
38     'Takuya Tsuchida',
39 )
40
41 __license__ = 'Public Domain'
42
43 import codecs
44 import getpass
45 import optparse
46 import os
47 import random
48 import re
49 import shlex
50 import subprocess
51 import sys
52
53
54 from .utils import (
55     compat_print,
56     DateRange,
57     decodeOption,
58     determine_ext,
59     DownloadError,
60     get_cachedir,
61     MaxDownloadsReached,
62     preferredencoding,
63     SameFileError,
64     std_headers,
65     write_string,
66 )
67 from .update import update_self
68 from .FileDownloader import (
69     FileDownloader,
70 )
71 from .extractor import gen_extractors
72 from .version import __version__
73 from .YoutubeDL import YoutubeDL
74 from .PostProcessor import (
75     FFmpegMetadataPP,
76     FFmpegVideoConvertor,
77     FFmpegExtractAudioPP,
78     FFmpegEmbedSubtitlePP,
79 )
80
81
82 def parseOpts(overrideArguments=None):
83     def _readOptions(filename_bytes):
84         try:
85             optionf = open(filename_bytes)
86         except IOError:
87             return [] # silently skip if file is not present
88         try:
89             res = []
90             for l in optionf:
91                 res += shlex.split(l, comments=True)
92         finally:
93             optionf.close()
94         return res
95
96     def _format_option_string(option):
97         ''' ('-o', '--option') -> -o, --format METAVAR'''
98
99         opts = []
100
101         if option._short_opts:
102             opts.append(option._short_opts[0])
103         if option._long_opts:
104             opts.append(option._long_opts[0])
105         if len(opts) > 1:
106             opts.insert(1, ', ')
107
108         if option.takes_value(): opts.append(' %s' % option.metavar)
109
110         return "".join(opts)
111
112     def _comma_separated_values_options_callback(option, opt_str, value, parser):
113         setattr(parser.values, option.dest, value.split(','))
114
115     def _find_term_columns():
116         columns = os.environ.get('COLUMNS', None)
117         if columns:
118             return int(columns)
119
120         try:
121             sp = subprocess.Popen(['stty', 'size'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
122             out,err = sp.communicate()
123             return int(out.split()[1])
124         except:
125             pass
126         return None
127
128     def _hide_login_info(opts):
129         opts = list(opts)
130         for private_opt in ['-p', '--password', '-u', '--username', '--video-password']:
131             try:
132                 i = opts.index(private_opt)
133                 opts[i+1] = '<PRIVATE>'
134             except ValueError:
135                 pass
136         return opts
137
138     max_width = 80
139     max_help_position = 80
140
141     # No need to wrap help messages if we're on a wide console
142     columns = _find_term_columns()
143     if columns: max_width = columns
144
145     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
146     fmt.format_option_strings = _format_option_string
147
148     kw = {
149         'version'   : __version__,
150         'formatter' : fmt,
151         'usage' : '%prog [options] url [url...]',
152         'conflict_handler' : 'resolve',
153     }
154
155     parser = optparse.OptionParser(**kw)
156
157     # option groups
158     general        = optparse.OptionGroup(parser, 'General Options')
159     selection      = optparse.OptionGroup(parser, 'Video Selection')
160     authentication = optparse.OptionGroup(parser, 'Authentication Options')
161     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
162     subtitles      = optparse.OptionGroup(parser, 'Subtitle Options')
163     downloader     = optparse.OptionGroup(parser, 'Download Options')
164     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
165     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
166     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
167
168     general.add_option('-h', '--help',
169             action='help', help='print this help text and exit')
170     general.add_option('-v', '--version',
171             action='version', help='print program version and exit')
172     general.add_option('-U', '--update',
173             action='store_true', dest='update_self', help='update this program to latest version. Make sure that you have sufficient permissions (run with sudo if needed)')
174     general.add_option('-i', '--ignore-errors',
175             action='store_true', dest='ignoreerrors', help='continue on download errors, for example to to skip unavailable videos in a playlist', default=False)
176     general.add_option('--abort-on-error',
177             action='store_false', dest='ignoreerrors',
178             help='Abort downloading of further videos (in the playlist or the command line) if an error occurs')
179     general.add_option('--dump-user-agent',
180             action='store_true', dest='dump_user_agent',
181             help='display the current browser identification', default=False)
182     general.add_option('--user-agent',
183             dest='user_agent', help='specify a custom user agent', metavar='UA')
184     general.add_option('--referer',
185             dest='referer', help='specify a custom referer, use if the video access is restricted to one domain',
186             metavar='REF', default=None)
187     general.add_option('--list-extractors',
188             action='store_true', dest='list_extractors',
189             help='List all supported extractors and the URLs they would handle', default=False)
190     general.add_option('--extractor-descriptions',
191             action='store_true', dest='list_extractor_descriptions',
192             help='Output descriptions of all supported extractors', default=False)
193     general.add_option('--proxy', dest='proxy', default=None, help='Use the specified HTTP/HTTPS proxy', metavar='URL')
194     general.add_option('--no-check-certificate', action='store_true', dest='no_check_certificate', default=False, help='Suppress HTTPS certificate validation.')
195     general.add_option(
196         '--cache-dir', dest='cachedir', default=get_cachedir(), metavar='DIR',
197         help='Location in the filesystem where youtube-dl can store downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl .')
198     general.add_option(
199         '--no-cache-dir', action='store_const', const=None, dest='cachedir',
200         help='Disable filesystem caching')
201
202
203     selection.add_option('--playlist-start',
204             dest='playliststart', metavar='NUMBER', help='playlist video to start at (default is %default)', default=1)
205     selection.add_option('--playlist-end',
206             dest='playlistend', metavar='NUMBER', help='playlist video to end at (default is last)', default=-1)
207     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
208     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
209     selection.add_option('--max-downloads', metavar='NUMBER',
210                          dest='max_downloads', type=int, default=None,
211                          help='Abort after downloading NUMBER files')
212     selection.add_option('--min-filesize', metavar='SIZE', dest='min_filesize', help="Do not download any videos smaller than SIZE (e.g. 50k or 44.6m)", default=None)
213     selection.add_option('--max-filesize', metavar='SIZE', dest='max_filesize', help="Do not download any videos larger than SIZE (e.g. 50k or 44.6m)", default=None)
214     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
215     selection.add_option('--datebefore', metavar='DATE', dest='datebefore', help='download only videos uploaded before this date', default=None)
216     selection.add_option('--dateafter', metavar='DATE', dest='dateafter', help='download only videos uploaded after this date', default=None)
217     selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
218     selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
219                          help='download only videos suitable for the given age',
220                          default=None, type=int)
221     selection.add_option('--download-archive', metavar='FILE',
222                          dest='download_archive',
223                          help='Download only videos not present in the archive file. Record all downloaded videos in it.')
224
225
226     authentication.add_option('-u', '--username',
227             dest='username', metavar='USERNAME', help='account username')
228     authentication.add_option('-p', '--password',
229             dest='password', metavar='PASSWORD', help='account password')
230     authentication.add_option('-n', '--netrc',
231             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
232     authentication.add_option('--video-password',
233             dest='videopassword', metavar='PASSWORD', help='video password (vimeo only)')
234
235
236     video_format.add_option('-f', '--format',
237             action='store', dest='format', metavar='FORMAT', default='best',
238             help='video format code, specifiy the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported')
239     video_format.add_option('--all-formats',
240             action='store_const', dest='format', help='download all available video formats', const='all')
241     video_format.add_option('--prefer-free-formats',
242             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
243     video_format.add_option('--max-quality',
244             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
245     video_format.add_option('-F', '--list-formats',
246             action='store_true', dest='listformats', help='list all available formats (currently youtube only)')
247
248     subtitles.add_option('--write-sub', '--write-srt',
249             action='store_true', dest='writesubtitles',
250             help='write subtitle file', default=False)
251     subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
252             action='store_true', dest='writeautomaticsub',
253             help='write automatic subtitle file (youtube only)', default=False)
254     subtitles.add_option('--all-subs',
255             action='store_true', dest='allsubtitles',
256             help='downloads all the available subtitles of the video', default=False)
257     subtitles.add_option('--list-subs',
258             action='store_true', dest='listsubtitles',
259             help='lists all available subtitles for the video', default=False)
260     subtitles.add_option('--sub-format',
261             action='store', dest='subtitlesformat', metavar='FORMAT',
262             help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
263     subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
264             action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
265             default=[], callback=_comma_separated_values_options_callback,
266             help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
267
268     downloader.add_option('-r', '--rate-limit',
269             dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
270     downloader.add_option('-R', '--retries',
271             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
272     downloader.add_option('--buffer-size',
273             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
274     downloader.add_option('--no-resize-buffer',
275             action='store_true', dest='noresizebuffer',
276             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
277     downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
278
279     verbosity.add_option('-q', '--quiet',
280             action='store_true', dest='quiet', help='activates quiet mode', default=False)
281     verbosity.add_option('-s', '--simulate',
282             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
283     verbosity.add_option('--skip-download',
284             action='store_true', dest='skip_download', help='do not download the video', default=False)
285     verbosity.add_option('-g', '--get-url',
286             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
287     verbosity.add_option('-e', '--get-title',
288             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
289     verbosity.add_option('--get-id',
290             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
291     verbosity.add_option('--get-thumbnail',
292             action='store_true', dest='getthumbnail',
293             help='simulate, quiet but print thumbnail URL', default=False)
294     verbosity.add_option('--get-description',
295             action='store_true', dest='getdescription',
296             help='simulate, quiet but print video description', default=False)
297     verbosity.add_option('--get-filename',
298             action='store_true', dest='getfilename',
299             help='simulate, quiet but print output filename', default=False)
300     verbosity.add_option('--get-format',
301             action='store_true', dest='getformat',
302             help='simulate, quiet but print output format', default=False)
303     verbosity.add_option('-j', '--dump-json',
304             action='store_true', dest='dumpjson',
305             help='simulate, quiet but print JSON information', default=False)
306     verbosity.add_option('--newline',
307             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
308     verbosity.add_option('--no-progress',
309             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
310     verbosity.add_option('--console-title',
311             action='store_true', dest='consoletitle',
312             help='display progress in console titlebar', default=False)
313     verbosity.add_option('-v', '--verbose',
314             action='store_true', dest='verbose', help='print various debugging information', default=False)
315     verbosity.add_option('--dump-intermediate-pages',
316             action='store_true', dest='dump_intermediate_pages', default=False,
317             help='print downloaded pages to debug problems(very verbose)')
318     verbosity.add_option('--write-pages',
319             action='store_true', dest='write_pages', default=False,
320             help='Write downloaded pages to files in the current directory')
321     verbosity.add_option('--youtube-print-sig-code',
322             action='store_true', dest='youtube_print_sig_code', default=False,
323             help=optparse.SUPPRESS_HELP)
324
325
326     filesystem.add_option('-t', '--title',
327             action='store_true', dest='usetitle', help='use title in file name (default)', default=False)
328     filesystem.add_option('--id',
329             action='store_true', dest='useid', help='use only video ID in file name', default=False)
330     filesystem.add_option('-l', '--literal',
331             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
332     filesystem.add_option('-A', '--auto-number',
333             action='store_true', dest='autonumber',
334             help='number downloaded files starting from 00000', default=False)
335     filesystem.add_option('-o', '--output',
336             dest='outtmpl', metavar='TEMPLATE',
337             help=('output filename template. Use %(title)s to get the title, '
338                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
339                   '%(autonumber)s to get an automatically incremented number, '
340                   '%(ext)s for the filename extension, '
341                   '%(format)s for the format description (like "22 - 1280x720" or "HD"),'
342                   '%(format_id)s for the unique id of the format (like Youtube\'s itags: "137"),'
343                   '%(upload_date)s for the upload date (YYYYMMDD), '
344                   '%(extractor)s for the provider (youtube, metacafe, etc), '
345                   '%(id)s for the video id , %(playlist)s for the playlist the video is in, '
346                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
347                   'Use - to output to stdout. Can also be used to download to a different directory, '
348                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
349     filesystem.add_option('--autonumber-size',
350             dest='autonumber_size', metavar='NUMBER',
351             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given')
352     filesystem.add_option('--restrict-filenames',
353             action='store_true', dest='restrictfilenames',
354             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
355     filesystem.add_option('-a', '--batch-file',
356             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
357     filesystem.add_option('-w', '--no-overwrites',
358             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
359     filesystem.add_option('-c', '--continue',
360             action='store_true', dest='continue_dl', help='force resume of partially downloaded files. By default, youtube-dl will resume downloads if possible.', default=True)
361     filesystem.add_option('--no-continue',
362             action='store_false', dest='continue_dl',
363             help='do not resume partially downloaded files (restart from beginning)')
364     filesystem.add_option('--cookies',
365             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
366     filesystem.add_option('--no-part',
367             action='store_true', dest='nopart', help='do not use .part files', default=False)
368     filesystem.add_option('--no-mtime',
369             action='store_false', dest='updatetime',
370             help='do not use the Last-modified header to set the file modification time', default=True)
371     filesystem.add_option('--write-description',
372             action='store_true', dest='writedescription',
373             help='write video description to a .description file', default=False)
374     filesystem.add_option('--write-info-json',
375             action='store_true', dest='writeinfojson',
376             help='write video metadata to a .info.json file', default=False)
377     filesystem.add_option('--write-annotations',
378             action='store_true', dest='writeannotations',
379             help='write video annotations to a .annotation file', default=False)
380     filesystem.add_option('--write-thumbnail',
381             action='store_true', dest='writethumbnail',
382             help='write thumbnail image to disk', default=False)
383
384
385     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
386             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
387     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
388             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
389     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
390             help='ffmpeg/avconv audio quality specification, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default 5)')
391     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
392             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
393     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
394             help='keeps the video file on disk after the post-processing; the video is erased by default')
395     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
396             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
397     postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
398             help='embed subtitles in the video (only for mp4 videos)')
399     postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
400             help='add metadata to the files')
401
402
403     parser.add_option_group(general)
404     parser.add_option_group(selection)
405     parser.add_option_group(downloader)
406     parser.add_option_group(filesystem)
407     parser.add_option_group(verbosity)
408     parser.add_option_group(video_format)
409     parser.add_option_group(subtitles)
410     parser.add_option_group(authentication)
411     parser.add_option_group(postproc)
412
413     if overrideArguments is not None:
414         opts, args = parser.parse_args(overrideArguments)
415         if opts.verbose:
416             write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
417     else:
418         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
419         if xdg_config_home:
420             userConfFile = os.path.join(xdg_config_home, 'youtube-dl', 'config')
421             if not os.path.isfile(userConfFile):
422                 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
423         else:
424             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl', 'config')
425             if not os.path.isfile(userConfFile):
426                 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
427         systemConf = _readOptions('/etc/youtube-dl.conf')
428         userConf = _readOptions(userConfFile)
429         commandLineConf = sys.argv[1:]
430         argv = systemConf + userConf + commandLineConf
431         opts, args = parser.parse_args(argv)
432         if opts.verbose:
433             write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
434             write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
435             write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
436
437     return parser, opts, args
438
439 def _real_main(argv=None):
440     # Compatibility fixes for Windows
441     if sys.platform == 'win32':
442         # https://github.com/rg3/youtube-dl/issues/820
443         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
444
445     parser, opts, args = parseOpts(argv)
446
447     # Set user agent
448     if opts.user_agent is not None:
449         std_headers['User-Agent'] = opts.user_agent
450
451     # Set referer
452     if opts.referer is not None:
453         std_headers['Referer'] = opts.referer
454
455     # Dump user agent
456     if opts.dump_user_agent:
457         compat_print(std_headers['User-Agent'])
458         sys.exit(0)
459
460     # Batch file verification
461     batchurls = []
462     if opts.batchfile is not None:
463         try:
464             if opts.batchfile == '-':
465                 batchfd = sys.stdin
466             else:
467                 batchfd = open(opts.batchfile, 'r')
468             batchurls = batchfd.readlines()
469             batchurls = [x.strip() for x in batchurls]
470             batchurls = [x for x in batchurls if len(x) > 0 and not re.search(r'^[#/;]', x)]
471             if opts.verbose:
472                 write_string(u'[debug] Batch file urls: ' + repr(batchurls) + u'\n')
473         except IOError:
474             sys.exit(u'ERROR: batch file could not be read')
475     all_urls = batchurls + args
476     all_urls = [url.strip() for url in all_urls]
477
478     extractors = gen_extractors()
479
480     if opts.list_extractors:
481         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
482             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
483             matchedUrls = [url for url in all_urls if ie.suitable(url)]
484             all_urls = [url for url in all_urls if url not in matchedUrls]
485             for mu in matchedUrls:
486                 compat_print(u'  ' + mu)
487         sys.exit(0)
488     if opts.list_extractor_descriptions:
489         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
490             if not ie._WORKING:
491                 continue
492             desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
493             if desc is False:
494                 continue
495             if hasattr(ie, 'SEARCH_KEY'):
496                 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise')
497                 _COUNTS = (u'', u'5', u'10', u'all')
498                 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
499             compat_print(desc)
500         sys.exit(0)
501
502
503     # Conflicting, missing and erroneous options
504     if opts.usenetrc and (opts.username is not None or opts.password is not None):
505         parser.error(u'using .netrc conflicts with giving username/password')
506     if opts.password is not None and opts.username is None:
507         parser.error(u' account username missing\n')
508     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
509         parser.error(u'using output template conflicts with using title, video ID or auto number')
510     if opts.usetitle and opts.useid:
511         parser.error(u'using title conflicts with using video ID')
512     if opts.username is not None and opts.password is None:
513         opts.password = getpass.getpass(u'Type account password and press return:')
514     if opts.ratelimit is not None:
515         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
516         if numeric_limit is None:
517             parser.error(u'invalid rate limit specified')
518         opts.ratelimit = numeric_limit
519     if opts.min_filesize is not None:
520         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
521         if numeric_limit is None:
522             parser.error(u'invalid min_filesize specified')
523         opts.min_filesize = numeric_limit
524     if opts.max_filesize is not None:
525         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
526         if numeric_limit is None:
527             parser.error(u'invalid max_filesize specified')
528         opts.max_filesize = numeric_limit
529     if opts.retries is not None:
530         try:
531             opts.retries = int(opts.retries)
532         except (TypeError, ValueError):
533             parser.error(u'invalid retry count specified')
534     if opts.buffersize is not None:
535         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
536         if numeric_buffersize is None:
537             parser.error(u'invalid buffer size specified')
538         opts.buffersize = numeric_buffersize
539     try:
540         opts.playliststart = int(opts.playliststart)
541         if opts.playliststart <= 0:
542             raise ValueError(u'Playlist start must be positive')
543     except (TypeError, ValueError):
544         parser.error(u'invalid playlist start number specified')
545     try:
546         opts.playlistend = int(opts.playlistend)
547         if opts.playlistend != -1 and (opts.playlistend <= 0 or opts.playlistend < opts.playliststart):
548             raise ValueError(u'Playlist end must be greater than playlist start')
549     except (TypeError, ValueError):
550         parser.error(u'invalid playlist end number specified')
551     if opts.extractaudio:
552         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
553             parser.error(u'invalid audio format specified')
554     if opts.audioquality:
555         opts.audioquality = opts.audioquality.strip('k').strip('K')
556         if not opts.audioquality.isdigit():
557             parser.error(u'invalid audio quality specified')
558     if opts.recodevideo is not None:
559         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg']:
560             parser.error(u'invalid video recode format specified')
561     if opts.date is not None:
562         date = DateRange.day(opts.date)
563     else:
564         date = DateRange(opts.dateafter, opts.datebefore)
565
566     # --all-sub automatically sets --write-sub if --write-auto-sub is not given
567     # this was the old behaviour if only --all-sub was given.
568     if opts.allsubtitles and (opts.writeautomaticsub == False):
569         opts.writesubtitles = True
570
571     if sys.version_info < (3,):
572         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
573         if opts.outtmpl is not None:
574             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
575     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
576             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
577             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
578             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
579             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
580             or (opts.useid and u'%(id)s.%(ext)s')
581             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
582             or u'%(title)s-%(id)s.%(ext)s')
583     if '%(ext)s' not in outtmpl and opts.extractaudio:
584         parser.error(u'Cannot download a video and extract audio into the same'
585                      u' file! Use "%%(ext)s" instead of %r' %
586                      determine_ext(outtmpl, u''))
587
588     ydl_opts = {
589         'usenetrc': opts.usenetrc,
590         'username': opts.username,
591         'password': opts.password,
592         'videopassword': opts.videopassword,
593         'quiet': (opts.quiet or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.dumpjson),
594         'forceurl': opts.geturl,
595         'forcetitle': opts.gettitle,
596         'forceid': opts.getid,
597         'forcethumbnail': opts.getthumbnail,
598         'forcedescription': opts.getdescription,
599         'forcefilename': opts.getfilename,
600         'forceformat': opts.getformat,
601         'forcejson': opts.dumpjson,
602         'simulate': opts.simulate,
603         'skip_download': (opts.skip_download or opts.simulate or opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.dumpjson),
604         'format': opts.format,
605         'format_limit': opts.format_limit,
606         'listformats': opts.listformats,
607         'outtmpl': outtmpl,
608         'autonumber_size': opts.autonumber_size,
609         'restrictfilenames': opts.restrictfilenames,
610         'ignoreerrors': opts.ignoreerrors,
611         'ratelimit': opts.ratelimit,
612         'nooverwrites': opts.nooverwrites,
613         'retries': opts.retries,
614         'buffersize': opts.buffersize,
615         'noresizebuffer': opts.noresizebuffer,
616         'continuedl': opts.continue_dl,
617         'noprogress': opts.noprogress,
618         'progress_with_newline': opts.progress_with_newline,
619         'playliststart': opts.playliststart,
620         'playlistend': opts.playlistend,
621         'noplaylist': opts.noplaylist,
622         'logtostderr': opts.outtmpl == '-',
623         'consoletitle': opts.consoletitle,
624         'nopart': opts.nopart,
625         'updatetime': opts.updatetime,
626         'writedescription': opts.writedescription,
627         'writeannotations': opts.writeannotations,
628         'writeinfojson': opts.writeinfojson,
629         'writethumbnail': opts.writethumbnail,
630         'writesubtitles': opts.writesubtitles,
631         'writeautomaticsub': opts.writeautomaticsub,
632         'allsubtitles': opts.allsubtitles,
633         'listsubtitles': opts.listsubtitles,
634         'subtitlesformat': opts.subtitlesformat,
635         'subtitleslangs': opts.subtitleslangs,
636         'matchtitle': decodeOption(opts.matchtitle),
637         'rejecttitle': decodeOption(opts.rejecttitle),
638         'max_downloads': opts.max_downloads,
639         'prefer_free_formats': opts.prefer_free_formats,
640         'verbose': opts.verbose,
641         'dump_intermediate_pages': opts.dump_intermediate_pages,
642         'write_pages': opts.write_pages,
643         'test': opts.test,
644         'keepvideo': opts.keepvideo,
645         'min_filesize': opts.min_filesize,
646         'max_filesize': opts.max_filesize,
647         'daterange': date,
648         'cachedir': opts.cachedir,
649         'youtube_print_sig_code': opts.youtube_print_sig_code,
650         'age_limit': opts.age_limit,
651         'download_archive': opts.download_archive,
652         'cookiefile': opts.cookiefile,
653         'nocheckcertificate': opts.no_check_certificate,
654     }
655
656     with YoutubeDL(ydl_opts) as ydl:
657         ydl.print_debug_header()
658         ydl.add_default_info_extractors()
659
660         # PostProcessors
661         # Add the metadata pp first, the other pps will copy it
662         if opts.addmetadata:
663             ydl.add_post_processor(FFmpegMetadataPP())
664         if opts.extractaudio:
665             ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
666         if opts.recodevideo:
667             ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
668         if opts.embedsubtitles:
669             ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
670
671         # Update version
672         if opts.update_self:
673             update_self(ydl.to_screen, opts.verbose)
674
675         # Maybe do nothing
676         if len(all_urls) < 1:
677             if not opts.update_self:
678                 parser.error(u'you must provide at least one URL')
679             else:
680                 sys.exit()
681
682         try:
683             retcode = ydl.download(all_urls)
684         except MaxDownloadsReached:
685             ydl.to_screen(u'--max-download limit reached, aborting.')
686             retcode = 101
687
688     sys.exit(retcode)
689
690
691 def main(argv=None):
692     try:
693         _real_main(argv)
694     except DownloadError:
695         sys.exit(1)
696     except SameFileError:
697         sys.exit(u'ERROR: fixed output name but more than one file to download')
698     except KeyboardInterrupt:
699         sys.exit(u'\nERROR: Interrupted by user')