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