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