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