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