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