Moved from os.system to subprocess.call
[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     'Michael Orlitzky',
41     'Chris Gahan',
42     'Saimadhav Heblikar',
43     'Mike Col',
44     'Oleg Prutz',
45     'pulpe',
46     'Andreas Schmitz',
47     'Michael Kaiser',
48     'Niklas Laxström',
49     'David Triendl',
50     'Anthony Weems',
51     'David Wagner',
52     'Juan C. Olivares',
53     'Mattias Harrysson',
54     'phaer',
55     'Sainyam Kapoor',
56     'Nicolas Évrard',
57     'Jason Normore',
58     'Hoje Lee',
59     'Adam Thalhammer',
60     'Georg Jähnig',
61     'Ralf Haring',
62     'Koki Takahashi',
63     'Ariset Llerena',
64     'Adam Malcontenti-Wilson',
65     'Tobias Bell',
66     'Naglis Jonaitis',
67     'Charles Chen',
68     'Hassaan Ali',
69     'Dobrosław Żybort',
70     'David Fabijan',
71     'Sebastian Haas',
72     'Alexander Kirk',
73     'Erik Johnson',
74 <<<<<<< HEAD
75     'Keith Beckman',
76     'Ole Ernst',
77 =======
78     'Aaron McDaniel (mcd1992)',
79 >>>>>>> Implemented --exec option.
80 )
81
82 __license__ = 'Public Domain'
83
84 import codecs
85 import io
86 import optparse
87 import os
88 import random
89 import shlex
90 import shutil
91 import sys
92
93
94 from .utils import (
95     compat_getpass,
96     compat_print,
97     DateRange,
98     DEFAULT_OUTTMPL,
99     decodeOption,
100     get_term_width,
101     DownloadError,
102     get_cachedir,
103     MaxDownloadsReached,
104     preferredencoding,
105     read_batch_urls,
106     SameFileError,
107     setproctitle,
108     std_headers,
109     write_string,
110 )
111 from .update import update_self
112 from .downloader import (
113     FileDownloader,
114 )
115 from .extractor import gen_extractors
116 from .version import __version__
117 from .YoutubeDL import YoutubeDL
118 from .postprocessor import (
119     AtomicParsleyPP,
120     FFmpegAudioFixPP,
121     FFmpegMetadataPP,
122     FFmpegVideoConvertor,
123     FFmpegExtractAudioPP,
124     FFmpegEmbedSubtitlePP,
125     XAttrMetadataPP,
126     ExecAfterDownloadPP,
127 )
128
129
130 def parseOpts(overrideArguments=None):
131     def _readOptions(filename_bytes, default=[]):
132         try:
133             optionf = open(filename_bytes)
134         except IOError:
135             return default  # silently skip if file is not present
136         try:
137             res = []
138             for l in optionf:
139                 res += shlex.split(l, comments=True)
140         finally:
141             optionf.close()
142         return res
143
144     def _readUserConf():
145         xdg_config_home = os.environ.get('XDG_CONFIG_HOME')
146         if xdg_config_home:
147             userConfFile = os.path.join(xdg_config_home, 'youtube-dl', 'config')
148             if not os.path.isfile(userConfFile):
149                 userConfFile = os.path.join(xdg_config_home, 'youtube-dl.conf')
150         else:
151             userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl', 'config')
152             if not os.path.isfile(userConfFile):
153                 userConfFile = os.path.join(os.path.expanduser('~'), '.config', 'youtube-dl.conf')
154         userConf = _readOptions(userConfFile, None)
155
156         if userConf is None:
157             appdata_dir = os.environ.get('appdata')
158             if appdata_dir:
159                 userConf = _readOptions(
160                     os.path.join(appdata_dir, 'youtube-dl', 'config'),
161                     default=None)
162                 if userConf is None:
163                     userConf = _readOptions(
164                         os.path.join(appdata_dir, 'youtube-dl', 'config.txt'),
165                         default=None)
166
167         if userConf is None:
168             userConf = _readOptions(
169                 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf'),
170                 default=None)
171         if userConf is None:
172             userConf = _readOptions(
173                 os.path.join(os.path.expanduser('~'), 'youtube-dl.conf.txt'),
174                 default=None)
175
176         if userConf is None:
177             userConf = []
178
179         return userConf
180
181     def _format_option_string(option):
182         ''' ('-o', '--option') -> -o, --format METAVAR'''
183
184         opts = []
185
186         if option._short_opts:
187             opts.append(option._short_opts[0])
188         if option._long_opts:
189             opts.append(option._long_opts[0])
190         if len(opts) > 1:
191             opts.insert(1, ', ')
192
193         if option.takes_value(): opts.append(' %s' % option.metavar)
194
195         return "".join(opts)
196
197     def _comma_separated_values_options_callback(option, opt_str, value, parser):
198         setattr(parser.values, option.dest, value.split(','))
199
200     def _hide_login_info(opts):
201         opts = list(opts)
202         for private_opt in ['-p', '--password', '-u', '--username', '--video-password']:
203             try:
204                 i = opts.index(private_opt)
205                 opts[i+1] = '<PRIVATE>'
206             except ValueError:
207                 pass
208         return opts
209
210     max_width = 80
211     max_help_position = 80
212
213     # No need to wrap help messages if we're on a wide console
214     columns = get_term_width()
215     if columns: max_width = columns
216
217     fmt = optparse.IndentedHelpFormatter(width=max_width, max_help_position=max_help_position)
218     fmt.format_option_strings = _format_option_string
219
220     kw = {
221         'version'   : __version__,
222         'formatter' : fmt,
223         'usage' : '%prog [options] url [url...]',
224         'conflict_handler' : 'resolve',
225     }
226
227     parser = optparse.OptionParser(**kw)
228
229     # option groups
230     general        = optparse.OptionGroup(parser, 'General Options')
231     selection      = optparse.OptionGroup(parser, 'Video Selection')
232     authentication = optparse.OptionGroup(parser, 'Authentication Options')
233     video_format   = optparse.OptionGroup(parser, 'Video Format Options')
234     subtitles      = optparse.OptionGroup(parser, 'Subtitle Options')
235     downloader     = optparse.OptionGroup(parser, 'Download Options')
236     postproc       = optparse.OptionGroup(parser, 'Post-processing Options')
237     filesystem     = optparse.OptionGroup(parser, 'Filesystem Options')
238     workarounds    = optparse.OptionGroup(parser, 'Workarounds')
239     verbosity      = optparse.OptionGroup(parser, 'Verbosity / Simulation Options')
240
241     general.add_option('-h', '--help',
242             action='help', help='print this help text and exit')
243     general.add_option('-v', '--version',
244             action='version', help='print program version and exit')
245     general.add_option('-U', '--update',
246             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)')
247     general.add_option('-i', '--ignore-errors',
248             action='store_true', dest='ignoreerrors', help='continue on download errors, for example to skip unavailable videos in a playlist', default=False)
249     general.add_option('--abort-on-error',
250             action='store_false', dest='ignoreerrors',
251             help='Abort downloading of further videos (in the playlist or the command line) if an error occurs')
252     general.add_option('--dump-user-agent',
253             action='store_true', dest='dump_user_agent',
254             help='display the current browser identification', default=False)
255     general.add_option('--list-extractors',
256             action='store_true', dest='list_extractors',
257             help='List all supported extractors and the URLs they would handle', default=False)
258     general.add_option('--extractor-descriptions',
259             action='store_true', dest='list_extractor_descriptions',
260             help='Output descriptions of all supported extractors', default=False)
261     general.add_option(
262         '--proxy', dest='proxy', default=None, metavar='URL',
263         help='Use the specified HTTP/HTTPS proxy. Pass in an empty string (--proxy "") for direct connection')
264     general.add_option(
265         '--socket-timeout', dest='socket_timeout',
266         type=float, default=None, help=u'Time to wait before giving up, in seconds')
267     general.add_option(
268         '--default-search',
269         dest='default_search', metavar='PREFIX',
270         help='Use this prefix for unqualified URLs. For example "gvsearch2:" downloads two videos from google videos for  youtube-dl "large apple". Use the value "auto" to let youtube-dl guess ("auto_warning" to emit a warning when guessing). "error" just throws an error. The default value "fixup_error" repairs broken URLs, but emits an error if this is not possible instead of searching.')
271     general.add_option(
272         '--ignore-config',
273         action='store_true',
274         help='Do not read configuration files. When given in the global configuration file /etc/youtube-dl.conf: do not read the user configuration in ~/.config/youtube-dl.conf (%APPDATA%/youtube-dl/config.txt on Windows)')
275
276     selection.add_option(
277         '--playlist-start',
278         dest='playliststart', metavar='NUMBER', default=1, type=int,
279         help='playlist video to start at (default is %default)')
280     selection.add_option(
281         '--playlist-end',
282         dest='playlistend', metavar='NUMBER', default=None, type=int,
283         help='playlist video to end at (default is last)')
284     selection.add_option('--match-title', dest='matchtitle', metavar='REGEX',help='download only matching titles (regex or caseless sub-string)')
285     selection.add_option('--reject-title', dest='rejecttitle', metavar='REGEX',help='skip download for matching titles (regex or caseless sub-string)')
286     selection.add_option('--max-downloads', metavar='NUMBER',
287                          dest='max_downloads', type=int, default=None,
288                          help='Abort after downloading NUMBER files')
289     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)
290     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)
291     selection.add_option('--date', metavar='DATE', dest='date', help='download only videos uploaded in this date', default=None)
292     selection.add_option(
293         '--datebefore', metavar='DATE', dest='datebefore', default=None,
294         help='download only videos uploaded on or before this date (i.e. inclusive)')
295     selection.add_option(
296         '--dateafter', metavar='DATE', dest='dateafter', default=None,
297         help='download only videos uploaded on or after this date (i.e. inclusive)')
298     selection.add_option(
299         '--min-views', metavar='COUNT', dest='min_views',
300         default=None, type=int,
301         help="Do not download any videos with less than COUNT views",)
302     selection.add_option(
303         '--max-views', metavar='COUNT', dest='max_views',
304         default=None, type=int,
305         help="Do not download any videos with more than COUNT views",)
306     selection.add_option('--no-playlist', action='store_true', dest='noplaylist', help='download only the currently playing video', default=False)
307     selection.add_option('--age-limit', metavar='YEARS', dest='age_limit',
308                          help='download only videos suitable for the given age',
309                          default=None, type=int)
310     selection.add_option('--download-archive', metavar='FILE',
311                          dest='download_archive',
312                          help='Download only videos not listed in the archive file. Record the IDs of all downloaded videos in it.')
313     selection.add_option(
314         '--include-ads', dest='include_ads',
315         action='store_true',
316         help='Download advertisements as well (experimental)')
317     selection.add_option(
318         '--youtube-include-dash-manifest', action='store_true',
319         dest='youtube_include_dash_manifest', default=False,
320         help='Try to download the DASH manifest on YouTube videos (experimental)')
321
322     authentication.add_option('-u', '--username',
323             dest='username', metavar='USERNAME', help='account username')
324     authentication.add_option('-p', '--password',
325             dest='password', metavar='PASSWORD', help='account password')
326     authentication.add_option('-2', '--twofactor',
327             dest='twofactor', metavar='TWOFACTOR', help='two-factor auth code')
328     authentication.add_option('-n', '--netrc',
329             action='store_true', dest='usenetrc', help='use .netrc authentication data', default=False)
330     authentication.add_option('--video-password',
331             dest='videopassword', metavar='PASSWORD', help='video password (vimeo, smotri)')
332
333
334     video_format.add_option('-f', '--format',
335             action='store', dest='format', metavar='FORMAT', default=None,
336             help='video format code, specify the order of preference using slashes: "-f 22/17/18". "-f mp4" and "-f flv" are also supported. You can also use the special names "best", "bestvideo", "bestaudio", "worst", "worstvideo" and "worstaudio". By default, youtube-dl will pick the best quality.')
337     video_format.add_option('--all-formats',
338             action='store_const', dest='format', help='download all available video formats', const='all')
339     video_format.add_option('--prefer-free-formats',
340             action='store_true', dest='prefer_free_formats', default=False, help='prefer free video formats unless a specific one is requested')
341     video_format.add_option('--max-quality',
342             action='store', dest='format_limit', metavar='FORMAT', help='highest quality format to download')
343     video_format.add_option('-F', '--list-formats',
344             action='store_true', dest='listformats', help='list all available formats')
345
346     subtitles.add_option('--write-sub', '--write-srt',
347             action='store_true', dest='writesubtitles',
348             help='write subtitle file', default=False)
349     subtitles.add_option('--write-auto-sub', '--write-automatic-sub',
350             action='store_true', dest='writeautomaticsub',
351             help='write automatic subtitle file (youtube only)', default=False)
352     subtitles.add_option('--all-subs',
353             action='store_true', dest='allsubtitles',
354             help='downloads all the available subtitles of the video', default=False)
355     subtitles.add_option('--list-subs',
356             action='store_true', dest='listsubtitles',
357             help='lists all available subtitles for the video', default=False)
358     subtitles.add_option('--sub-format',
359             action='store', dest='subtitlesformat', metavar='FORMAT',
360             help='subtitle format (default=srt) ([sbv/vtt] youtube only)', default='srt')
361     subtitles.add_option('--sub-lang', '--sub-langs', '--srt-lang',
362             action='callback', dest='subtitleslangs', metavar='LANGS', type='str',
363             default=[], callback=_comma_separated_values_options_callback,
364             help='languages of the subtitles to download (optional) separated by commas, use IETF language tags like \'en,pt\'')
365
366     downloader.add_option('-r', '--rate-limit',
367             dest='ratelimit', metavar='LIMIT', help='maximum download rate in bytes per second (e.g. 50K or 4.2M)')
368     downloader.add_option('-R', '--retries',
369             dest='retries', metavar='RETRIES', help='number of retries (default is %default)', default=10)
370     downloader.add_option('--buffer-size',
371             dest='buffersize', metavar='SIZE', help='size of download buffer (e.g. 1024 or 16K) (default is %default)', default="1024")
372     downloader.add_option('--no-resize-buffer',
373             action='store_true', dest='noresizebuffer',
374             help='do not automatically adjust the buffer size. By default, the buffer size is automatically resized from an initial value of SIZE.', default=False)
375     downloader.add_option('--test', action='store_true', dest='test', default=False, help=optparse.SUPPRESS_HELP)
376
377     workarounds.add_option(
378         '--encoding', dest='encoding', metavar='ENCODING',
379         help='Force the specified encoding (experimental)')
380     workarounds.add_option(
381         '--no-check-certificate', action='store_true',
382         dest='no_check_certificate', default=False,
383         help='Suppress HTTPS certificate validation.')
384     workarounds.add_option(
385         '--prefer-insecure', '--prefer-unsecure', action='store_true', dest='prefer_insecure',
386         help='Use an unencrypted connection to retrieve information about the video. (Currently supported only for YouTube)')
387     workarounds.add_option(
388         '--user-agent', metavar='UA',
389         dest='user_agent', help='specify a custom user agent')
390     workarounds.add_option(
391         '--referer', metavar='REF',
392         dest='referer', default=None,
393         help='specify a custom referer, use if the video access is restricted to one domain',
394     )
395     workarounds.add_option(
396         '--add-header', metavar='FIELD:VALUE',
397         dest='headers', action='append',
398         help='specify a custom HTTP header and its value, separated by a colon \':\'. You can use this option multiple times',
399     )
400     workarounds.add_option(
401         '--bidi-workaround', dest='bidi_workaround', action='store_true',
402         help=u'Work around terminals that lack bidirectional text support. Requires bidiv or fribidi executable in PATH')
403
404     verbosity.add_option('-q', '--quiet',
405             action='store_true', dest='quiet', help='activates quiet mode', default=False)
406     verbosity.add_option(
407         '--no-warnings',
408         dest='no_warnings', action='store_true', default=False,
409         help='Ignore warnings')
410     verbosity.add_option('-s', '--simulate',
411             action='store_true', dest='simulate', help='do not download the video and do not write anything to disk', default=False)
412     verbosity.add_option('--skip-download',
413             action='store_true', dest='skip_download', help='do not download the video', default=False)
414     verbosity.add_option('-g', '--get-url',
415             action='store_true', dest='geturl', help='simulate, quiet but print URL', default=False)
416     verbosity.add_option('-e', '--get-title',
417             action='store_true', dest='gettitle', help='simulate, quiet but print title', default=False)
418     verbosity.add_option('--get-id',
419             action='store_true', dest='getid', help='simulate, quiet but print id', default=False)
420     verbosity.add_option('--get-thumbnail',
421             action='store_true', dest='getthumbnail',
422             help='simulate, quiet but print thumbnail URL', default=False)
423     verbosity.add_option('--get-description',
424             action='store_true', dest='getdescription',
425             help='simulate, quiet but print video description', default=False)
426     verbosity.add_option('--get-duration',
427             action='store_true', dest='getduration',
428             help='simulate, quiet but print video length', default=False)
429     verbosity.add_option('--get-filename',
430             action='store_true', dest='getfilename',
431             help='simulate, quiet but print output filename', default=False)
432     verbosity.add_option('--get-format',
433             action='store_true', dest='getformat',
434             help='simulate, quiet but print output format', default=False)
435     verbosity.add_option('-j', '--dump-json',
436             action='store_true', dest='dumpjson',
437             help='simulate, quiet but print JSON information. See --output for a description of available keys.', default=False)
438     verbosity.add_option('--newline',
439             action='store_true', dest='progress_with_newline', help='output progress bar as new lines', default=False)
440     verbosity.add_option('--no-progress',
441             action='store_true', dest='noprogress', help='do not print progress bar', default=False)
442     verbosity.add_option('--console-title',
443             action='store_true', dest='consoletitle',
444             help='display progress in console titlebar', default=False)
445     verbosity.add_option('-v', '--verbose',
446             action='store_true', dest='verbose', help='print various debugging information', default=False)
447     verbosity.add_option('--dump-intermediate-pages',
448             action='store_true', dest='dump_intermediate_pages', default=False,
449             help='print downloaded pages to debug problems (very verbose)')
450     verbosity.add_option('--write-pages',
451             action='store_true', dest='write_pages', default=False,
452             help='Write downloaded intermediary pages to files in the current directory to debug problems')
453     verbosity.add_option('--youtube-print-sig-code',
454             action='store_true', dest='youtube_print_sig_code', default=False,
455             help=optparse.SUPPRESS_HELP)
456     verbosity.add_option('--print-traffic',
457             dest='debug_printtraffic', action='store_true', default=False,
458             help='Display sent and read HTTP traffic')
459
460
461     filesystem.add_option('-a', '--batch-file',
462             dest='batchfile', metavar='FILE', help='file containing URLs to download (\'-\' for stdin)')
463     filesystem.add_option('--id',
464             action='store_true', dest='useid', help='use only video ID in file name', default=False)
465     filesystem.add_option('-A', '--auto-number',
466             action='store_true', dest='autonumber',
467             help='number downloaded files starting from 00000', default=False)
468     filesystem.add_option('-o', '--output',
469             dest='outtmpl', metavar='TEMPLATE',
470             help=('output filename template. Use %(title)s to get the title, '
471                   '%(uploader)s for the uploader name, %(uploader_id)s for the uploader nickname if different, '
472                   '%(autonumber)s to get an automatically incremented number, '
473                   '%(ext)s for the filename extension, '
474                   '%(format)s for the format description (like "22 - 1280x720" or "HD"), '
475                   '%(format_id)s for the unique id of the format (like Youtube\'s itags: "137"), '
476                   '%(upload_date)s for the upload date (YYYYMMDD), '
477                   '%(extractor)s for the provider (youtube, metacafe, etc), '
478                   '%(id)s for the video id, %(playlist)s for the playlist the video is in, '
479                   '%(playlist_index)s for the position in the playlist and %% for a literal percent. '
480                   '%(height)s and %(width)s for the width and height of the video format. '
481                   '%(resolution)s for a textual description of the resolution of the video format. '
482                   'Use - to output to stdout. Can also be used to download to a different directory, '
483                   'for example with -o \'/my/downloads/%(uploader)s/%(title)s-%(id)s.%(ext)s\' .'))
484     filesystem.add_option('--autonumber-size',
485             dest='autonumber_size', metavar='NUMBER',
486             help='Specifies the number of digits in %(autonumber)s when it is present in output filename template or --auto-number option is given')
487     filesystem.add_option('--restrict-filenames',
488             action='store_true', dest='restrictfilenames',
489             help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames', default=False)
490     filesystem.add_option('-t', '--title',
491             action='store_true', dest='usetitle', help='[deprecated] use title in file name (default)', default=False)
492     filesystem.add_option('-l', '--literal',
493             action='store_true', dest='usetitle', help='[deprecated] alias of --title', default=False)
494     filesystem.add_option('-w', '--no-overwrites',
495             action='store_true', dest='nooverwrites', help='do not overwrite files', default=False)
496     filesystem.add_option('-c', '--continue',
497             action='store_true', dest='continue_dl', help='force resume of partially downloaded files. By default, youtube-dl will resume downloads if possible.', default=True)
498     filesystem.add_option('--no-continue',
499             action='store_false', dest='continue_dl',
500             help='do not resume partially downloaded files (restart from beginning)')
501     filesystem.add_option('--no-part',
502             action='store_true', dest='nopart', help='do not use .part files', default=False)
503     filesystem.add_option('--no-mtime',
504             action='store_false', dest='updatetime',
505             help='do not use the Last-modified header to set the file modification time', default=True)
506     filesystem.add_option('--write-description',
507             action='store_true', dest='writedescription',
508             help='write video description to a .description file', default=False)
509     filesystem.add_option('--write-info-json',
510             action='store_true', dest='writeinfojson',
511             help='write video metadata to a .info.json file', default=False)
512     filesystem.add_option('--write-annotations',
513             action='store_true', dest='writeannotations',
514             help='write video annotations to a .annotation file', default=False)
515     filesystem.add_option('--write-thumbnail',
516             action='store_true', dest='writethumbnail',
517             help='write thumbnail image to disk', default=False)
518     filesystem.add_option('--load-info',
519             dest='load_info_filename', metavar='FILE',
520             help='json file containing the video information (created with the "--write-json" option)')
521     filesystem.add_option('--cookies',
522             dest='cookiefile', metavar='FILE', help='file to read cookies from and dump cookie jar in')
523     filesystem.add_option(
524         '--cache-dir', dest='cachedir', default=get_cachedir(), metavar='DIR',
525         help='Location in the filesystem where youtube-dl can store some downloaded information permanently. By default $XDG_CACHE_HOME/youtube-dl or ~/.cache/youtube-dl . At the moment, only YouTube player files (for videos with obfuscated signatures) are cached, but that may change.')
526     filesystem.add_option(
527         '--no-cache-dir', action='store_const', const=None, dest='cachedir',
528         help='Disable filesystem caching')
529     filesystem.add_option(
530         '--rm-cache-dir', action='store_true', dest='rm_cachedir',
531         help='Delete all filesystem cache files')
532
533
534     postproc.add_option('-x', '--extract-audio', action='store_true', dest='extractaudio', default=False,
535             help='convert video files to audio-only files (requires ffmpeg or avconv and ffprobe or avprobe)')
536     postproc.add_option('--audio-format', metavar='FORMAT', dest='audioformat', default='best',
537             help='"best", "aac", "vorbis", "mp3", "m4a", "opus", or "wav"; best by default')
538     postproc.add_option('--audio-quality', metavar='QUALITY', dest='audioquality', default='5',
539             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)')
540     postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
541             help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm|mkv)')
542     postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
543             help='keeps the video file on disk after the post-processing; the video is erased by default')
544     postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
545             help='do not overwrite post-processed files; the post-processed files are overwritten by default')
546     postproc.add_option('--embed-subs', action='store_true', dest='embedsubtitles', default=False,
547             help='embed subtitles in the video (only for mp4 videos)')
548     postproc.add_option('--embed-thumbnail', action='store_true', dest='embedthumbnail', default=False,
549             help='embed thumbnail in the audio as cover art')
550     postproc.add_option('--add-metadata', action='store_true', dest='addmetadata', default=False,
551             help='write metadata to the video file')
552     postproc.add_option('--xattrs', action='store_true', dest='xattrs', default=False,
553             help='write metadata to the video file\'s xattrs (using dublin core and xdg standards)')
554     postproc.add_option('--prefer-avconv', action='store_false', dest='prefer_ffmpeg',
555         help='Prefer avconv over ffmpeg for running the postprocessors (default)')
556     postproc.add_option('--prefer-ffmpeg', action='store_true', dest='prefer_ffmpeg',
557         help='Prefer ffmpeg over avconv for running the postprocessors')
558     postproc.add_option('--exec', metavar='', action='store', dest='execstring',
559         help='Execute a command on the file after downloading, similar to find\'s -exec syntax. Must be enclosed in quotes. Example: --exec \'adb push {} /sdcard/Music/ && rm {}\'' )
560
561     parser.add_option_group(general)
562     parser.add_option_group(selection)
563     parser.add_option_group(downloader)
564     parser.add_option_group(filesystem)
565     parser.add_option_group(verbosity)
566     parser.add_option_group(workarounds)
567     parser.add_option_group(video_format)
568     parser.add_option_group(subtitles)
569     parser.add_option_group(authentication)
570     parser.add_option_group(postproc)
571
572     if overrideArguments is not None:
573         opts, args = parser.parse_args(overrideArguments)
574         if opts.verbose:
575             write_string(u'[debug] Override config: ' + repr(overrideArguments) + '\n')
576     else:
577         commandLineConf = sys.argv[1:]
578         if '--ignore-config' in commandLineConf:
579             systemConf = []
580             userConf = []
581         else:
582             systemConf = _readOptions('/etc/youtube-dl.conf')
583             if '--ignore-config' in systemConf:
584                 userConf = []
585             else:
586                 userConf = _readUserConf()
587         argv = systemConf + userConf + commandLineConf
588
589         opts, args = parser.parse_args(argv)
590         if opts.verbose:
591             write_string(u'[debug] System config: ' + repr(_hide_login_info(systemConf)) + '\n')
592             write_string(u'[debug] User config: ' + repr(_hide_login_info(userConf)) + '\n')
593             write_string(u'[debug] Command-line args: ' + repr(_hide_login_info(commandLineConf)) + '\n')
594
595     return parser, opts, args
596
597
598 def _real_main(argv=None):
599     # Compatibility fixes for Windows
600     if sys.platform == 'win32':
601         # https://github.com/rg3/youtube-dl/issues/820
602         codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
603
604     setproctitle(u'youtube-dl')
605
606     parser, opts, args = parseOpts(argv)
607
608     # Set user agent
609     if opts.user_agent is not None:
610         std_headers['User-Agent'] = opts.user_agent
611
612     # Set referer
613     if opts.referer is not None:
614         std_headers['Referer'] = opts.referer
615
616     # Custom HTTP headers
617     if opts.headers is not None:
618         for h in opts.headers:
619             if h.find(':', 1) < 0:
620                 parser.error(u'wrong header formatting, it should be key:value, not "%s"'%h)
621             key, value = h.split(':', 2)
622             if opts.verbose:
623                 write_string(u'[debug] Adding header from command line option %s:%s\n'%(key, value))
624             std_headers[key] = value
625
626     # Dump user agent
627     if opts.dump_user_agent:
628         compat_print(std_headers['User-Agent'])
629         sys.exit(0)
630
631     # Batch file verification
632     batch_urls = []
633     if opts.batchfile is not None:
634         try:
635             if opts.batchfile == '-':
636                 batchfd = sys.stdin
637             else:
638                 batchfd = io.open(opts.batchfile, 'r', encoding='utf-8', errors='ignore')
639             batch_urls = read_batch_urls(batchfd)
640             if opts.verbose:
641                 write_string(u'[debug] Batch file urls: ' + repr(batch_urls) + u'\n')
642         except IOError:
643             sys.exit(u'ERROR: batch file could not be read')
644     all_urls = batch_urls + args
645     all_urls = [url.strip() for url in all_urls]
646     _enc = preferredencoding()
647     all_urls = [url.decode(_enc, 'ignore') if isinstance(url, bytes) else url for url in all_urls]
648
649     extractors = gen_extractors()
650
651     if opts.list_extractors:
652         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
653             compat_print(ie.IE_NAME + (' (CURRENTLY BROKEN)' if not ie._WORKING else ''))
654             matchedUrls = [url for url in all_urls if ie.suitable(url)]
655             for mu in matchedUrls:
656                 compat_print(u'  ' + mu)
657         sys.exit(0)
658     if opts.list_extractor_descriptions:
659         for ie in sorted(extractors, key=lambda ie: ie.IE_NAME.lower()):
660             if not ie._WORKING:
661                 continue
662             desc = getattr(ie, 'IE_DESC', ie.IE_NAME)
663             if desc is False:
664                 continue
665             if hasattr(ie, 'SEARCH_KEY'):
666                 _SEARCHES = (u'cute kittens', u'slithering pythons', u'falling cat', u'angry poodle', u'purple fish', u'running tortoise', u'sleeping bunny')
667                 _COUNTS = (u'', u'5', u'10', u'all')
668                 desc += u' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES))
669             compat_print(desc)
670         sys.exit(0)
671
672
673     # Conflicting, missing and erroneous options
674     if opts.usenetrc and (opts.username is not None or opts.password is not None):
675         parser.error(u'using .netrc conflicts with giving username/password')
676     if opts.password is not None and opts.username is None:
677         parser.error(u'account username missing\n')
678     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid):
679         parser.error(u'using output template conflicts with using title, video ID or auto number')
680     if opts.usetitle and opts.useid:
681         parser.error(u'using title conflicts with using video ID')
682     if opts.username is not None and opts.password is None:
683         opts.password = compat_getpass(u'Type account password and press [Return]: ')
684     if opts.ratelimit is not None:
685         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit)
686         if numeric_limit is None:
687             parser.error(u'invalid rate limit specified')
688         opts.ratelimit = numeric_limit
689     if opts.min_filesize is not None:
690         numeric_limit = FileDownloader.parse_bytes(opts.min_filesize)
691         if numeric_limit is None:
692             parser.error(u'invalid min_filesize specified')
693         opts.min_filesize = numeric_limit
694     if opts.max_filesize is not None:
695         numeric_limit = FileDownloader.parse_bytes(opts.max_filesize)
696         if numeric_limit is None:
697             parser.error(u'invalid max_filesize specified')
698         opts.max_filesize = numeric_limit
699     if opts.retries is not None:
700         try:
701             opts.retries = int(opts.retries)
702         except (TypeError, ValueError):
703             parser.error(u'invalid retry count specified')
704     if opts.buffersize is not None:
705         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize)
706         if numeric_buffersize is None:
707             parser.error(u'invalid buffer size specified')
708         opts.buffersize = numeric_buffersize
709     if opts.playliststart <= 0:
710         raise ValueError(u'Playlist start must be positive')
711     if opts.playlistend not in (-1, None) and opts.playlistend < opts.playliststart:
712         raise ValueError(u'Playlist end must be greater than playlist start')
713     if opts.extractaudio:
714         if opts.audioformat not in ['best', 'aac', 'mp3', 'm4a', 'opus', 'vorbis', 'wav']:
715             parser.error(u'invalid audio format specified')
716     if opts.audioquality:
717         opts.audioquality = opts.audioquality.strip('k').strip('K')
718         if not opts.audioquality.isdigit():
719             parser.error(u'invalid audio quality specified')
720     if opts.recodevideo is not None:
721         if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg', 'mkv']:
722             parser.error(u'invalid video recode format specified')
723     if opts.date is not None:
724         date = DateRange.day(opts.date)
725     else:
726         date = DateRange(opts.dateafter, opts.datebefore)
727     if opts.default_search not in ('auto', 'auto_warning', 'error', 'fixup_error', None) and ':' not in opts.default_search:
728         parser.error(u'--default-search invalid; did you forget a colon (:) at the end?')
729
730     # Do not download videos when there are audio-only formats
731     if opts.extractaudio and not opts.keepvideo and opts.format is None:
732         opts.format = 'bestaudio/best'
733
734     # --all-sub automatically sets --write-sub if --write-auto-sub is not given
735     # this was the old behaviour if only --all-sub was given.
736     if opts.allsubtitles and (opts.writeautomaticsub == False):
737         opts.writesubtitles = True
738
739     if sys.version_info < (3,):
740         # In Python 2, sys.argv is a bytestring (also note http://bugs.python.org/issue2128 for Windows systems)
741         if opts.outtmpl is not None:
742             opts.outtmpl = opts.outtmpl.decode(preferredencoding())
743     outtmpl =((opts.outtmpl is not None and opts.outtmpl)
744             or (opts.format == '-1' and opts.usetitle and u'%(title)s-%(id)s-%(format)s.%(ext)s')
745             or (opts.format == '-1' and u'%(id)s-%(format)s.%(ext)s')
746             or (opts.usetitle and opts.autonumber and u'%(autonumber)s-%(title)s-%(id)s.%(ext)s')
747             or (opts.usetitle and u'%(title)s-%(id)s.%(ext)s')
748             or (opts.useid and u'%(id)s.%(ext)s')
749             or (opts.autonumber and u'%(autonumber)s-%(id)s.%(ext)s')
750             or DEFAULT_OUTTMPL)
751     if not os.path.splitext(outtmpl)[1] and opts.extractaudio:
752         parser.error(u'Cannot download a video and extract audio into the same'
753                      u' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
754                      u' template'.format(outtmpl))
755
756     any_printing = opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.getduration or opts.dumpjson
757     download_archive_fn = os.path.expanduser(opts.download_archive) if opts.download_archive is not None else opts.download_archive
758
759     ydl_opts = {
760         'usenetrc': opts.usenetrc,
761         'username': opts.username,
762         'password': opts.password,
763         'twofactor': opts.twofactor,
764         'videopassword': opts.videopassword,
765         'quiet': (opts.quiet or any_printing),
766         'no_warnings': opts.no_warnings,
767         'forceurl': opts.geturl,
768         'forcetitle': opts.gettitle,
769         'forceid': opts.getid,
770         'forcethumbnail': opts.getthumbnail,
771         'forcedescription': opts.getdescription,
772         'forceduration': opts.getduration,
773         'forcefilename': opts.getfilename,
774         'forceformat': opts.getformat,
775         'forcejson': opts.dumpjson,
776         'simulate': opts.simulate,
777         'skip_download': (opts.skip_download or opts.simulate or any_printing),
778         'format': opts.format,
779         'format_limit': opts.format_limit,
780         'listformats': opts.listformats,
781         'outtmpl': outtmpl,
782         'autonumber_size': opts.autonumber_size,
783         'restrictfilenames': opts.restrictfilenames,
784         'ignoreerrors': opts.ignoreerrors,
785         'ratelimit': opts.ratelimit,
786         'nooverwrites': opts.nooverwrites,
787         'retries': opts.retries,
788         'buffersize': opts.buffersize,
789         'noresizebuffer': opts.noresizebuffer,
790         'continuedl': opts.continue_dl,
791         'noprogress': opts.noprogress,
792         'progress_with_newline': opts.progress_with_newline,
793         'playliststart': opts.playliststart,
794         'playlistend': opts.playlistend,
795         'noplaylist': opts.noplaylist,
796         'logtostderr': opts.outtmpl == '-',
797         'consoletitle': opts.consoletitle,
798         'nopart': opts.nopart,
799         'updatetime': opts.updatetime,
800         'writedescription': opts.writedescription,
801         'writeannotations': opts.writeannotations,
802         'writeinfojson': opts.writeinfojson,
803         'writethumbnail': opts.writethumbnail,
804         'writesubtitles': opts.writesubtitles,
805         'writeautomaticsub': opts.writeautomaticsub,
806         'allsubtitles': opts.allsubtitles,
807         'listsubtitles': opts.listsubtitles,
808         'subtitlesformat': opts.subtitlesformat,
809         'subtitleslangs': opts.subtitleslangs,
810         'matchtitle': decodeOption(opts.matchtitle),
811         'rejecttitle': decodeOption(opts.rejecttitle),
812         'max_downloads': opts.max_downloads,
813         'prefer_free_formats': opts.prefer_free_formats,
814         'verbose': opts.verbose,
815         'dump_intermediate_pages': opts.dump_intermediate_pages,
816         'write_pages': opts.write_pages,
817         'test': opts.test,
818         'keepvideo': opts.keepvideo,
819         'min_filesize': opts.min_filesize,
820         'max_filesize': opts.max_filesize,
821         'min_views': opts.min_views,
822         'max_views': opts.max_views,
823         'daterange': date,
824         'cachedir': opts.cachedir,
825         'youtube_print_sig_code': opts.youtube_print_sig_code,
826         'age_limit': opts.age_limit,
827         'download_archive': download_archive_fn,
828         'cookiefile': opts.cookiefile,
829         'nocheckcertificate': opts.no_check_certificate,
830         'prefer_insecure': opts.prefer_insecure,
831         'proxy': opts.proxy,
832         'socket_timeout': opts.socket_timeout,
833         'bidi_workaround': opts.bidi_workaround,
834         'debug_printtraffic': opts.debug_printtraffic,
835         'prefer_ffmpeg': opts.prefer_ffmpeg,
836         'include_ads': opts.include_ads,
837         'default_search': opts.default_search,
838         'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,
839         'encoding': opts.encoding,
840         'execstring': opts.execstring,
841     }
842
843     with YoutubeDL(ydl_opts) as ydl:
844         ydl.print_debug_header()
845         ydl.add_default_info_extractors()
846
847         # PostProcessors
848         # Add the metadata pp first, the other pps will copy it
849         if opts.addmetadata:
850             ydl.add_post_processor(FFmpegMetadataPP())
851         if opts.extractaudio:
852             ydl.add_post_processor(FFmpegExtractAudioPP(preferredcodec=opts.audioformat, preferredquality=opts.audioquality, nopostoverwrites=opts.nopostoverwrites))
853         if opts.recodevideo:
854             ydl.add_post_processor(FFmpegVideoConvertor(preferedformat=opts.recodevideo))
855         if opts.embedsubtitles:
856             ydl.add_post_processor(FFmpegEmbedSubtitlePP(subtitlesformat=opts.subtitlesformat))
857         if opts.xattrs:
858             ydl.add_post_processor(XAttrMetadataPP())
859         if opts.embedthumbnail:
860             if not opts.addmetadata:
861                 ydl.add_post_processor(FFmpegAudioFixPP())
862             ydl.add_post_processor(AtomicParsleyPP())
863
864
865         # Please keep ExecAfterDownload towards the bottom as it allows the user to modify the final file in any way.
866         # So if the user is able to remove the file before your postprocessor runs it might cause a few problems.
867         if opts.execstring:
868             ydl.add_post_processor(ExecAfterDownloadPP(verboseOutput=opts.verbose,commandString=opts.execstring))
869
870         # Update version
871         if opts.update_self:
872             update_self(ydl.to_screen, opts.verbose)
873
874         # Remove cache dir
875         if opts.rm_cachedir:
876             if opts.cachedir is None:
877                 ydl.to_screen(u'No cache dir specified (Did you combine --no-cache-dir and --rm-cache-dir?)')
878             else:
879                 if ('.cache' not in opts.cachedir) or ('youtube-dl' not in opts.cachedir):
880                     ydl.to_screen(u'Not removing directory %s - this does not look like a cache dir')
881                     retcode = 141
882                 else:
883                     ydl.to_screen(
884                         u'Removing cache dir %s .' % opts.cachedir,
885                         skip_eol=True)
886                     if os.path.exists(opts.cachedir):
887                         ydl.to_screen(u'.', skip_eol=True)
888                         shutil.rmtree(opts.cachedir)
889                     ydl.to_screen(u'.')
890
891         # Maybe do nothing
892         if (len(all_urls) < 1) and (opts.load_info_filename is None):
893             if not (opts.update_self or opts.rm_cachedir):
894                 parser.error(u'you must provide at least one URL')
895             else:
896                 sys.exit()
897
898         try:
899             if opts.load_info_filename is not None:
900                 retcode = ydl.download_with_info_file(opts.load_info_filename)
901             else:
902                 retcode = ydl.download(all_urls)
903         except MaxDownloadsReached:
904             ydl.to_screen(u'--max-download limit reached, aborting.')
905             retcode = 101
906
907     sys.exit(retcode)
908
909
910 def main(argv=None):
911     try:
912         _real_main(argv)
913     except DownloadError:
914         sys.exit(1)
915     except SameFileError:
916         sys.exit(u'ERROR: fixed output name but more than one file to download')
917     except KeyboardInterrupt:
918         sys.exit(u'\nERROR: Interrupted by user')