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