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