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