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