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