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